]> Cypherpunks repositories - keks.git/commitdiff
Reorganise code, import third-parties
authorSergey Matveev <stargrave@stargrave.org>
Thu, 13 Feb 2025 15:34:33 +0000 (18:34 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Fri, 14 Feb 2025 08:40:37 +0000 (11:40 +0300)
91 files changed:
go/cm/algo.go [deleted file]
go/cm/av.go
go/cm/cmd/enctool/main.go
go/cm/cmd/hshtool/main.go
go/cm/cmd/keytool/main.go
go/cm/cmd/sigtool/main.go
go/cm/ed25519-blake2b/.gitignore [deleted file]
go/cm/ed25519-blake2b/clean [deleted file]
go/cm/ed25519-blake2b/ed25519-to-blake2b.patch [deleted file]
go/cm/ed25519-blake2b/mk-from-go [deleted file]
go/cm/enc/balloon.go [moved from go/cm/encrypted/balloon.go with 100% similarity]
go/cm/enc/dem.go [new file with mode: 0644]
go/cm/enc/kem.go [moved from go/cm/encrypted/kem.go with 100% similarity]
go/cm/enc/magic.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/README [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/algo.go [moved from go/cm/mceliece6960119-x25519/algo.go with 100% similarity]
go/cm/enc/mceliece6960119-x25519/kp.go [moved from go/cm/mceliece6960119-x25519/kp.go with 83% similarity]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/benes.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/fft.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/controlbits.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/djbsort.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/fft_const.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/powers.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e12/gf4096.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e13/gf8192.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/mceliece.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/operations.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/pk_gen.go [new file with mode: 0644]
go/cm/enc/mceliece6960119-x25519/mceliece6960119/vec.go [new file with mode: 0644]
go/cm/enc/sntrup4591761-x25519/algo.go [moved from go/cm/sntrup4591761-x25519/algo.go with 100% similarity]
go/cm/enc/sntrup4591761-x25519/kp.go [moved from go/cm/sntrup4591761-x25519/kp.go with 100% similarity]
go/cm/go.mod
go/cm/go.sum
go/cm/hash/algo.go
go/cm/hash/blake2b/algo.go [moved from go/cm/ed25519-blake2b/algo.go with 100% similarity]
go/cm/hash/blake2b/hasher.go [moved from go/cm/ed25519-blake2b/hasher.go with 100% similarity]
go/cm/hash/gost/algo.go [new file with mode: 0644]
go/cm/hash/gost/hasher.go [moved from go/cm/gost/hasher.go with 90% similarity]
go/cm/hash/magic.go [new file with mode: 0644]
go/cm/mceliece6960119-x25519/SOURCE [deleted file]
go/cm/sign/ed25519-blake2b/README [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/algo.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/ed25519/ed25519.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/alias/alias.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/byteorder/byteorder.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/doc.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/edwards25519.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/fe_amd64_asm.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/go.mod [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/go.sum [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64.s [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64_noasm.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64.s [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64_noasm.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/field/fe_generic.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/scalar.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/scalar_fiat.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/scalarmult.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/constant_time.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_amd64.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_amd64.s [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_arm64.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_arm64.s [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_generic.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_loong64.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_loong64.s [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_ppc64x.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_ppc64x.s [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/edwards25519/tables.go [new file with mode: 0644]
go/cm/sign/ed25519-blake2b/kp.go [moved from go/cm/ed25519-blake2b/kp.go with 82% similarity]
go/cm/sign/ed25519-blake2b/signer.go [moved from go/cm/ed25519-blake2b/signer.go with 70% similarity]
go/cm/sign/ed25519-blake2b/verify.go [moved from go/cm/ed25519-blake2b/verify.go with 69% similarity]
go/cm/sign/gost/gost.go [moved from go/cm/gost/gost.go with 86% similarity]
go/cm/sign/gost/kp.go [moved from go/cm/gost/kp.go with 100% similarity]
go/cm/sign/gost/signer.go [moved from go/cm/gost/signer.go with 86% similarity]
go/cm/sign/gost/verify.go [moved from go/cm/gost/verify.go with 94% similarity]
go/cm/sign/iface.go
go/cm/sign/mode.go [deleted file]
go/cm/sign/mode/mode.go [new file with mode: 0644]
go/cm/sign/prv.go [moved from go/cm/prv.go with 80% similarity]
go/cm/sign/pub.go [moved from go/cm/pub.go with 93% similarity]
go/cm/sign/signed.go [moved from go/cm/signed.go with 94% similarity]
go/cm/sntrup4591761-x25519/go.mod [deleted file]
go/cm/sntrup4591761-x25519/go.sum [deleted file]
go/cm/utils/utils.go [deleted file]
go/go.mod
go/go.sum

diff --git a/go/cm/algo.go b/go/cm/algo.go
deleted file mode 100644 (file)
index 94b0da7..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// GoKEKS/CM -- KEKS-encoded cryptographic messages
-// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation, version 3 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-package cm
-
-import (
-       "go.cypherpunks.su/keks"
-       ed25519blake2b "go.cypherpunks.su/keks/cm/ed25519-blake2b"
-       "go.cypherpunks.su/keks/cm/gost"
-       mceliece6960119x25519 "go.cypherpunks.su/keks/cm/mceliece6960119-x25519"
-       sntrup4591761x25519 "go.cypherpunks.su/keks/cm/sntrup4591761-x25519"
-)
-
-const (
-       BalloonBLAKE2bHKDF                       = "balloon-blake2b-hkdf"
-       ChaCha20Poly1305                         = "chacha20poly1305"
-       ClassicMcEliece6960119X25519             = mceliece6960119x25519.ClassicMcEliece6960119X25519
-       ClassicMcEliece6960119X25519HKDFSHAKE256 = mceliece6960119x25519.ClassicMcEliece6960119X25519HKDFSHAKE256
-       Ed25519BLAKE2b                           = ed25519blake2b.Ed25519BLAKE2b
-       Ed25519PhBLAKE2b                         = ed25519blake2b.Ed25519PhBLAKE2b
-       Ed25519PhBLAKE2bMerkle                   = ed25519blake2b.Ed25519PhBLAKE2bMerkle
-       GOST3410256A                             = gost.GOST3410256A
-       GOST3410256AMerkle                       = gost.GOST3410256AMerkle
-       GOST3410512C                             = gost.GOST3410512C
-       GOST3410512CMerkle                       = gost.GOST3410512CMerkle
-       SNTRUP4591761X25519                      = sntrup4591761x25519.SNTRUP4591761X25519
-       SNTRUP4591761X25519HKDFBLAKE2b           = sntrup4591761x25519.SNTRUP4591761X25519HKDFBLAKE2b
-
-       EncryptedMagic = keks.Magic("cm/encrypted")
-       HashedMagic    = keks.Magic("cm/hashed")
-       PrvMagic       = keks.Magic("cm/prv")
-)
index fa920cbb9798e7dba461a4f24ab910309ab4a750cd921dab4748373a96ad314b..3e4d05a46eb2eaec026e262449074adb041a026974a1bbcfee60e649a63bc515 100644 (file)
@@ -1,59 +1,7 @@
-// GoKEKS/CM -- KEKS-encoded cryptographic messages
-// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation, version 3 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
 package cm
 
-import (
-       "bytes"
-       "hash"
-
-       "github.com/google/uuid"
-
-       "go.cypherpunks.su/keks"
-       cmhash "go.cypherpunks.su/keks/cm/hash"
-)
-
 // Algorithm-value often used structure.
 type AV struct {
        A string `keks:"a"`
        V []byte `keks:"v"`
 }
-
-// Calculate UUID of the AV. UUIDv4 is generated from the hash output of
-// the av structure. Hash algorithm selection depends on av.A. uuid.Nil
-// is returned if algorithm is not supported.
-func (av *AV) Id() (id uuid.UUID) {
-       var hasher hash.Hash
-       switch av.A {
-       case Ed25519BLAKE2b, SNTRUP4591761X25519:
-               hasher = cmhash.ByName(cmhash.BLAKE2b256)
-       case GOST3410256A, GOST3410512C:
-               hasher = cmhash.ByName(cmhash.Streebog256)
-       case ClassicMcEliece6960119X25519:
-               hasher = cmhash.ByName(cmhash.SHAKE128)
-       default:
-               id = uuid.Nil
-               return
-       }
-       _, err := keks.Encode(hasher, av, nil)
-       if err != nil {
-               panic(err)
-       }
-       id, err = uuid.NewRandomFromReader(bytes.NewReader(hasher.Sum(nil)))
-       if err != nil {
-               panic(err)
-       }
-       return
-}
index e5213a42124aa78fb52658c586057bbbba09c0ce9b6630573649f3d0ec522877..c9c12fd50a956012f0eb7ee0344b47317abf5d038b3a2086acf1dafb2e5c8eda 100644 (file)
@@ -28,8 +28,6 @@ import (
        "log"
        "os"
 
-       circlkem "github.com/cloudflare/circl/kem"
-       "github.com/cloudflare/circl/kem/mceliece/mceliece6960119"
        "github.com/companyzero/sntrup4591761"
        "github.com/google/uuid"
        "go.cypherpunks.su/balloon/v3"
@@ -39,9 +37,12 @@ import (
 
        "go.cypherpunks.su/keks"
        "go.cypherpunks.su/keks/cm"
-       cmenc "go.cypherpunks.su/keks/cm/encrypted"
+       cmenc "go.cypherpunks.su/keks/cm/enc"
+       mceliece6960119x25519 "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519"
+       mceliece6960119 "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119"
+       sntrup4591761x25519 "go.cypherpunks.su/keks/cm/enc/sntrup4591761-x25519"
        cmhash "go.cypherpunks.su/keks/cm/hash"
-       "go.cypherpunks.su/keks/cm/utils"
+       "go.cypherpunks.su/keks/cm/sign"
        "go.cypherpunks.su/keks/types"
 )
 
@@ -53,6 +54,14 @@ func blake2bHash() hash.Hash {
        return h
 }
 
+func mustReadFile(p string) []byte {
+       data, err := os.ReadFile(p)
+       if err != nil {
+               log.Fatalln("read:", p, err)
+       }
+       return data
+}
+
 func readPasswd(prompt string) (passwd []byte) {
        if raw := os.Getenv("ENCTOOL_PASSPHRASE"); raw != "" {
                return []byte(raw)
@@ -87,9 +96,9 @@ func main() {
        balloonT := flag.Int("balloon-t", 3, "Balloon's time cost")
        balloonP := flag.Int("balloon-p", 2, "Balloon's number of threads")
        doDecrypt := flag.Bool("d", false, "Decrypt")
-       var pubs []*cm.Pub
+       var pubs []*sign.Pub
        flag.Func("pub", "Path to public key to encrypt to", func(v string) error {
-               signed, err := cm.PubParse(utils.MustReadFile(v))
+               signed, err := sign.PubParse(mustReadFile(v))
                if err != nil {
                        return err
                }
@@ -97,8 +106,8 @@ func main() {
                if load.KU == nil {
                        log.Println(v, "does not have key usages")
                } else {
-                       if _, ok := (*load.KU)[cm.KUKEM]; !ok {
-                               log.Println(v, "does not have", cm.KUKEM, "key usage")
+                       if _, ok := (*load.KU)[sign.KUKEM]; !ok {
+                               log.Println(v, "does not have", sign.KUKEM, "key usage")
                        }
                }
                if len(load.Pub) != 1 {
@@ -109,8 +118,8 @@ func main() {
        })
        var prvs []*cm.AV
        flag.Func("prv", "Our private keys for decryption", func(v string) (err error) {
-               magic, data := keks.StripMagic(utils.MustReadFile(v))
-               if magic == "" || magic != cm.PrvMagic {
+               magic, data := keks.StripMagic(mustReadFile(v))
+               if magic == "" || magic != sign.PrvMagic {
                        return errors.New("wrong magic")
                }
                var av cm.AV
@@ -136,7 +145,7 @@ func main() {
                        if t != types.Magic {
                                log.Fatal("no magic met")
                        }
-                       if d.Iter().Magic() != cm.EncryptedMagic {
+                       if d.Iter().Magic() != cmenc.Magic {
                                log.Fatal("wrong magic")
                        }
                }
@@ -148,7 +157,7 @@ func main() {
                                log.Fatal(err)
                        }
                }
-               if encrypted.DEM.A != cm.ChaCha20Poly1305 {
+               if encrypted.DEM.A != cmenc.ChaCha20Poly1305 {
                        log.Fatalln("unsupported DEM:", encrypted.DEM.A)
                }
                if len(encrypted.KEM) == 0 {
@@ -156,7 +165,7 @@ func main() {
                }
                for kemIdx, kem := range encrypted.KEM {
                        switch kem.A {
-                       case cm.BalloonBLAKE2bHKDF:
+                       case cmenc.BalloonBLAKE2bHKDF:
                                if !*passphrase {
                                        log.Println(kemIdx, kem.A, "skipping because no -passwd")
                                        continue
@@ -195,7 +204,7 @@ func main() {
                                        }
                                        cek = cekp
                                }
-                       case cm.SNTRUP4591761X25519HKDFBLAKE2b:
+                       case sntrup4591761x25519.SNTRUP4591761X25519HKDFBLAKE2b:
                                if len(prvs) == 0 {
                                        log.Println(kemIdx, kem.A, "skipping because no -prv")
                                        continue
@@ -207,7 +216,7 @@ func main() {
                                        log.Fatalln("invalid encap len")
                                }
                                for _, prv := range prvs {
-                                       if prv.A != cm.SNTRUP4591761X25519 {
+                                       if prv.A != sntrup4591761x25519.SNTRUP4591761X25519 {
                                                continue
                                        }
                                        if len(prv.V) != sntrup4591761.PrivateKeySize+32 {
@@ -279,7 +288,7 @@ func main() {
                                                break
                                        }
                                }
-                       case cm.ClassicMcEliece6960119X25519HKDFSHAKE256:
+                       case mceliece6960119x25519.ClassicMcEliece6960119X25519HKDFSHAKE256:
                                if len(prvs) == 0 {
                                        log.Println(kemIdx, kem.A, "skipping because no -prv")
                                        continue
@@ -287,19 +296,18 @@ func main() {
                                if kem.Encap == nil {
                                        log.Fatalln("missing encap")
                                }
-                               scheme := mceliece6960119.Scheme()
-                               if len(*kem.Encap) != scheme.CiphertextSize()+32 {
+                               if len(*kem.Encap) != mceliece6960119.CiphertextSize+32 {
                                        log.Fatalln("invalid encap len")
                                }
                                for _, prv := range prvs {
-                                       if prv.A != cm.ClassicMcEliece6960119X25519 {
+                                       if prv.A != mceliece6960119x25519.ClassicMcEliece6960119X25519 {
                                                continue
                                        }
-                                       if len(prv.V) != scheme.PrivateKeySize()+32 {
+                                       if len(prv.V) != mceliece6960119.PrivateKeySize+32 {
                                                log.Fatalln("invalid private keys len")
                                        }
-                                       var ourMcEliece circlkem.PrivateKey
-                                       ourMcEliece, err = scheme.UnmarshalBinaryPrivateKey(
+                                       var ourMcEliece *mceliece6960119.PrivateKey
+                                       ourMcEliece, err = mceliece6960119.UnmarshalBinaryPrivateKey(
                                                prv.V[:len(prv.V)-32],
                                        )
                                        if err != nil {
@@ -313,7 +321,7 @@ func main() {
                                        }
                                        theirMcEliece := (*kem.Encap)[:len(*kem.Encap)-32]
                                        var keyMcEliece []byte
-                                       keyMcEliece, err = scheme.Decapsulate(ourMcEliece, theirMcEliece)
+                                       keyMcEliece, err = mceliece6960119.Decapsulate(ourMcEliece, theirMcEliece)
                                        if err != nil {
                                                log.Fatal(err)
                                        }
@@ -418,7 +426,7 @@ func main() {
                                log.Fatal(err)
                        }
                        kem := cmenc.KEM{
-                               A:    cm.BalloonBLAKE2bHKDF,
+                               A:    cmenc.BalloonBLAKE2bHKDF,
                                Salt: &bSalt,
                                Cost: &cmenc.BalloonCost{
                                        S: uint64(*balloonS),
@@ -450,7 +458,7 @@ func main() {
                }
                for _, pub := range pubs {
                        switch pub.A {
-                       case cm.SNTRUP4591761X25519:
+                       case sntrup4591761x25519.SNTRUP4591761X25519:
                                if len(pub.V) != sntrup4591761.PublicKeySize+32 {
                                        log.Fatalln("invalid public keys len")
                                }
@@ -483,7 +491,7 @@ func main() {
                                if err != nil {
                                        log.Fatal(err)
                                }
-                               kem := cmenc.KEM{A: cm.SNTRUP4591761X25519HKDFBLAKE2b}
+                               kem := cmenc.KEM{A: sntrup4591761x25519.SNTRUP4591761X25519HKDFBLAKE2b}
                                encap := append(ciphertext[:], ourPubX25519.Bytes()...)
                                kem.Encap = &encap
                                {
@@ -515,13 +523,12 @@ func main() {
                                        kem.To = &pub.Id
                                }
                                kems = append(kems, kem)
-                       case cm.ClassicMcEliece6960119X25519:
-                               scheme := mceliece6960119.Scheme()
-                               if len(pub.V) != scheme.PublicKeySize()+32 {
+                       case mceliece6960119x25519.ClassicMcEliece6960119X25519:
+                               if len(pub.V) != mceliece6960119.PublicKeySize+32 {
                                        log.Fatalln("invalid public keys len")
                                }
-                               var theirMcEliece circlkem.PublicKey
-                               theirMcEliece, err = scheme.UnmarshalBinaryPublicKey(
+                               var theirMcEliece *mceliece6960119.PublicKey
+                               theirMcEliece, err = mceliece6960119.UnmarshalBinaryPublicKey(
                                        pub.V[:len(pub.V)-32],
                                )
                                if err != nil {
@@ -535,7 +542,7 @@ func main() {
                                }
                                var ciphertext []byte
                                var keyMcEliece []byte
-                               ciphertext, keyMcEliece, err = scheme.Encapsulate(theirMcEliece)
+                               ciphertext, keyMcEliece, err = mceliece6960119.Encapsulate(theirMcEliece)
                                if err != nil {
                                        log.Fatal(err)
                                }
@@ -550,7 +557,7 @@ func main() {
                                if err != nil {
                                        log.Fatal(err)
                                }
-                               kem := cmenc.KEM{A: cm.ClassicMcEliece6960119X25519HKDFSHAKE256}
+                               kem := cmenc.KEM{A: mceliece6960119x25519.ClassicMcEliece6960119X25519HKDFSHAKE256}
                                encap := append(ciphertext[:], ourPubX25519.Bytes()...)
                                kem.Encap = &encap
                                {
@@ -591,13 +598,13 @@ func main() {
                }
                {
                        var hdr bytes.Buffer
-                       if _, err = keks.Encode(&hdr, cm.EncryptedMagic, nil); err != nil {
+                       if _, err = keks.Encode(&hdr, cmenc.Magic, nil); err != nil {
                                log.Fatal(err)
                        }
                        if _, err = keks.Encode(&hdr, &cmenc.Encrypted{
                                Salt: salt,
                                KEM:  kems,
-                               DEM:  cmenc.DEM{A: cm.ChaCha20Poly1305},
+                               DEM:  cmenc.DEM{A: cmenc.ChaCha20Poly1305},
                        }, nil); err != nil {
                                log.Fatal(err)
                        }
index eab23995ab3e8cefe5c0ee71807134453874ae58a22b899928f80e2ee3b8828e..6c2b9e36939a1193287ed06d900e72ba3abb7ed5ad419d4a014ad58035dc144d 100644 (file)
@@ -11,9 +11,9 @@ import (
 
        "go.cypherpunks.su/gogost/v6/gost34112012256"
        "go.cypherpunks.su/gogost/v6/gost34112012512"
-       ed25519blake2b "go.cypherpunks.su/keks/cm/ed25519-blake2b"
-       "go.cypherpunks.su/keks/cm/gost"
        cmhash "go.cypherpunks.su/keks/cm/hash"
+       cmblake2b "go.cypherpunks.su/keks/cm/hash/blake2b"
+       "go.cypherpunks.su/keks/cm/hash/gost"
        "go.cypherpunks.su/keks/cm/hash/merkle"
 )
 
@@ -37,7 +37,7 @@ func main() {
        var hasher *merkle.Hasher
        switch *algo {
        case cmhash.BLAKE2bMerkle:
-               hasher = ed25519blake2b.NewMerkleHasher(chunkLen, *workers).(*merkle.Hasher)
+               hasher = cmblake2b.NewMerkleHasher(chunkLen, *workers).(*merkle.Hasher)
        case cmhash.SHA2512 + "-merkle":
                hasher = merkle.NewHasherPrefixed(sha512.New, chunkLen, *workers)
        case cmhash.SHAKE128Merkle:
index 5822ace7115c2a743c693e01ddcb920a44d0d47803edf5c154262e9ba166d113..1b74bfc09c14162851539e3a7718d8a00a1f393f457cbe6620c4156a3b6e853c 100644 (file)
@@ -20,22 +20,32 @@ import (
        "errors"
        "flag"
        "fmt"
+       "hash"
        "log"
        "os"
        "sort"
        "strings"
        "time"
 
+       "github.com/google/uuid"
        "go.cypherpunks.su/keks"
        "go.cypherpunks.su/keks/cm"
-       ed25519blake2b "go.cypherpunks.su/keks/cm/ed25519-blake2b"
-       "go.cypherpunks.su/keks/cm/gost"
-       mceliece6960119x25519 "go.cypherpunks.su/keks/cm/mceliece6960119-x25519"
+       mceliece6960119x25519 "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519"
+       sntrup4591761x25519 "go.cypherpunks.su/keks/cm/enc/sntrup4591761-x25519"
+       cmhash "go.cypherpunks.su/keks/cm/hash"
        "go.cypherpunks.su/keks/cm/sign"
-       sntrup4591761x25519 "go.cypherpunks.su/keks/cm/sntrup4591761-x25519"
-       "go.cypherpunks.su/keks/cm/utils"
+       ed25519blake2b "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b"
+       "go.cypherpunks.su/keks/cm/sign/gost"
 )
 
+func mustReadFile(p string) []byte {
+       data, err := os.ReadFile(p)
+       if err != nil {
+               log.Fatalln("read:", p, err)
+       }
+       return data
+}
+
 func main() {
        flag.Usage = usage
        ku := make(map[string]*struct{})
@@ -73,7 +83,8 @@ func main() {
                "Optional notBefore, \"2006-01-02 15:04:05\" format")
        lifetime := flag.Uint("lifetime", 365,
                "Lifetime of the certification, days")
-       algo := flag.String("algo", cm.Ed25519BLAKE2b, "Public key algorithm")
+       algo := flag.String("algo", ed25519blake2b.Ed25519BLAKE2b,
+               "Public key algorithm")
        issuingPrv := flag.String("ca-prv", "",
                "Path to private key file for issuing with")
        prvPath := flag.String("prv", "", "Path to private key file")
@@ -86,11 +97,11 @@ func main() {
 
        if *doList {
                algos := []string{
-                       cm.Ed25519BLAKE2b,
-                       cm.GOST3410256A,
-                       cm.GOST3410512C,
-                       cm.SNTRUP4591761X25519,
-                       cm.ClassicMcEliece6960119X25519,
+                       ed25519blake2b.Ed25519BLAKE2b,
+                       gost.GOST3410256A,
+                       gost.GOST3410512C,
+                       sntrup4591761x25519.SNTRUP4591761X25519,
+                       mceliece6960119x25519.ClassicMcEliece6960119X25519,
                }
                sort.Strings(algos)
                for _, s := range algos {
@@ -116,10 +127,10 @@ func main() {
        till := since.Add(time.Duration(*lifetime) * 24 * time.Hour)
 
        var caPrv sign.Iface
-       var caPubs []*cm.Signed
+       var caPubs []*sign.Signed
        for _, issuingPub := range issuingPubs {
-               var signed *cm.Signed
-               signed, err = cm.PubParse(utils.MustReadFile(issuingPub))
+               var signed *sign.Signed
+               signed, err = sign.PubParse(mustReadFile(issuingPub))
                if err != nil {
                        log.Fatal(err)
                }
@@ -129,15 +140,15 @@ func main() {
                if *issuingPrv == "" {
                        log.Fatal("no -ca-prv is set")
                }
-               caPrv, _, err = cm.PrvParse(utils.MustReadFile(*issuingPrv))
+               caPrv, _, err = sign.PrvParse(mustReadFile(*issuingPrv))
                if err != nil {
                        log.Fatal(err)
                }
        }
 
        if *verify {
-               var signed *cm.Signed
-               signed, err = cm.PubParse(utils.MustReadFile(*pubPath))
+               var signed *sign.Signed
+               signed, err = sign.PubParse(mustReadFile(*pubPath))
                if err != nil {
                        log.Fatal(err)
                }
@@ -149,10 +160,10 @@ func main() {
        }
 
        var prvRaw []byte
-       var pubLoad *cm.PubLoad
-       var signed *cm.Signed
+       var pubLoad *sign.PubLoad
+       var signed *sign.Signed
        if caPrv != nil {
-               signed, err = cm.PubParse(utils.MustReadFile(*pubPath))
+               signed, err = sign.PubParse(mustReadFile(*pubPath))
                if err != nil {
                        log.Fatal(err)
                }
@@ -166,13 +177,13 @@ func main() {
                        log.Fatal("no -prv is set")
                }
                switch *algo {
-               case cm.Ed25519BLAKE2b:
+               case ed25519blake2b.Ed25519BLAKE2b:
                        _, prvRaw, pub, err = ed25519blake2b.NewKeypair()
-               case cm.GOST3410256A, cm.GOST3410512C:
+               case gost.GOST3410256A, gost.GOST3410512C:
                        _, prvRaw, pub, err = gost.NewKeypair(*algo)
-               case cm.SNTRUP4591761X25519:
+               case sntrup4591761x25519.SNTRUP4591761X25519:
                        prvRaw, pub, err = sntrup4591761x25519.NewKeypair()
-               case cm.ClassicMcEliece6960119X25519:
+               case mceliece6960119x25519.ClassicMcEliece6960119X25519:
                        prvRaw, pub, err = mceliece6960119x25519.NewKeypair()
                default:
                        err = errors.New("unknown -algo specified")
@@ -182,7 +193,7 @@ func main() {
                }
                {
                        var buf bytes.Buffer
-                       if _, err = keks.Encode(&buf, cm.PrvMagic, nil); err != nil {
+                       if _, err = keks.Encode(&buf, sign.PrvMagic, nil); err != nil {
                                log.Fatal(err)
                        }
                        if _, err = keks.Encode(&buf, cm.AV{A: *algo, V: prvRaw}, nil); err != nil {
@@ -194,12 +205,30 @@ func main() {
                        }
                }
                {
-                       pubMap := cm.Pub{A: *algo, V: pub}
+                       pubMap := sign.Pub{A: *algo, V: pub}
                        {
                                av := cm.AV{A: *algo, V: pub}
-                               pubMap.Id = av.Id()
+                               var hasher hash.Hash
+                               switch av.A {
+                               case ed25519blake2b.Ed25519BLAKE2b, sntrup4591761x25519.SNTRUP4591761X25519:
+                                       hasher = cmhash.ByName(cmhash.BLAKE2b256)
+                               case gost.GOST3410256A, gost.GOST3410512C:
+                                       hasher = cmhash.ByName(cmhash.Streebog256)
+                               case mceliece6960119x25519.ClassicMcEliece6960119X25519:
+                                       hasher = cmhash.ByName(cmhash.SHAKE128)
+                               default:
+                                       log.Fatal("unsupported algorithm")
+                               }
+                               _, err = keks.Encode(hasher, av, nil)
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               pubMap.Id, err = uuid.NewRandomFromReader(bytes.NewReader(hasher.Sum(nil)))
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
                        }
-                       pubLoad = &cm.PubLoad{Subj: subj, Pub: []cm.Pub{pubMap}}
+                       pubLoad = &sign.PubLoad{Subj: subj, Pub: []sign.Pub{pubMap}}
                }
                if len(ku) > 0 {
                        pubLoad.KU = &ku
@@ -208,7 +237,7 @@ func main() {
 
        {
                pubLoadAny := any(pubLoad)
-               signed = &cm.Signed{Load: cm.SignedLoad{T: "pub", V: &pubLoadAny}}
+               signed = &sign.Signed{Load: sign.SignedLoad{T: "pub", V: &pubLoadAny}}
        }
 
        if caPrv != nil {
@@ -221,7 +250,7 @@ func main() {
 
        {
                var buf bytes.Buffer
-               if _, err = keks.Encode(&buf, cm.PubMagic, nil); err != nil {
+               if _, err = keks.Encode(&buf, sign.PubMagic, nil); err != nil {
                        log.Fatal(err)
                }
                if _, err = keks.Encode(&buf, signed, nil); err != nil {
index afc919285f60d9bf4aea98090720648500720a83e096212930194cc1c35540e0..92c64f5afda0913d840a7fe7cfa9516caa6107e4ad44622ffaf26acc4174e6b6 100644 (file)
@@ -29,15 +29,22 @@ import (
        "github.com/google/uuid"
 
        "go.cypherpunks.su/keks"
-       "go.cypherpunks.su/keks/cm"
        cmhash "go.cypherpunks.su/keks/cm/hash"
        "go.cypherpunks.su/keks/cm/sign"
-       "go.cypherpunks.su/keks/cm/utils"
+       "go.cypherpunks.su/keks/cm/sign/mode"
        "go.cypherpunks.su/keks/types"
 )
 
 const BlobChunkLen = 128 * 1024
 
+func mustReadFile(p string) []byte {
+       data, err := os.ReadFile(p)
+       if err != nil {
+               log.Fatalln("read:", p, err)
+       }
+       return data
+}
+
 func main() {
        log.SetFlags(log.Lshortfile)
        flag.Usage = usage
@@ -62,7 +69,7 @@ func main() {
        if *pubPath == "" {
                log.Fatal("no -pub is set")
        }
-       pub, err := cm.PubParse(utils.MustReadFile(*pubPath))
+       pub, err := sign.PubParse(mustReadFile(*pubPath))
        if err != nil {
                log.Fatal(err)
        }
@@ -75,18 +82,18 @@ func main() {
                if err != nil {
                        log.Fatal(err)
                }
-               if t != types.Magic || decoder.Iter().Magic() != cm.SignedMagic {
+               if t != types.Magic || decoder.Iter().Magic() != sign.SignedMagic {
                        log.Fatal("wrong magic")
                }
                decoder = keks.NewDecoderFromReader(stdin, nil)
                if _, err = decoder.Parse(); err != nil {
                        log.Fatal(err)
                }
-               var prehash cm.SignedPrehash
-               var signed cm.Signed
+               var prehash sign.SignedPrehash
+               var signed sign.Signed
                err = decoder.UnmarshalStruct(&prehash)
                var hasher hash.Hash
-               if err == nil && prehash.T == sign.PrehashT {
+               if err == nil && prehash.T == mode.PrehashT {
                        if len(prehash.Sigs) == 0 {
                                log.Fatal("prehash: no sigs")
                        }
@@ -126,7 +133,7 @@ func main() {
                if err != nil {
                        log.Fatal(err)
                }
-               if err = cm.SignedValidate(&signed); err != nil {
+               if err = sign.SignedValidate(&signed); err != nil {
                        log.Fatal(err)
                }
                if len(signed.Sigs) == 0 {
@@ -169,20 +176,20 @@ func main() {
                        log.Fatal("no -prv is set")
                }
                var signer sign.Iface
-               signer, _, err = cm.PrvParse(utils.MustReadFile(*prvPath))
+               signer, _, err = sign.PrvParse(mustReadFile(*prvPath))
                if err != nil {
                        log.Fatal(err)
                }
                if *doMerkle {
-                       err = signer.SetMode(sign.ModeMerkle)
+                       err = signer.SetMode(mode.Merkle)
                } else {
-                       err = signer.SetMode(sign.ModePrehash)
+                       err = signer.SetMode(mode.Prehash)
                }
                if err != nil {
                        log.Fatal(err)
                }
 
-               if _, err = keks.Encode(os.Stdout, cm.SignedMagic, nil); err != nil {
+               if _, err = keks.Encode(os.Stdout, sign.SignedMagic, nil); err != nil {
                        log.Fatal(err)
                }
                if *detached {
@@ -190,8 +197,8 @@ func main() {
                                log.Fatal(err)
                        }
                } else {
-                       if _, err = keks.Encode(os.Stdout, cm.SignedPrehash{
-                               T:    sign.PrehashT,
+                       if _, err = keks.Encode(os.Stdout, sign.SignedPrehash{
+                               T:    mode.PrehashT,
                                Sigs: map[string]*struct{}{signer.Algo(): nil},
                        }, nil); err != nil {
                                log.Fatal(err)
@@ -212,9 +219,9 @@ func main() {
                                log.Fatal(err)
                        }
                }
-               var signed cm.Signed
+               var signed sign.Signed
                signed.Load.T = *typ
-               var sigTbs cm.SigTBS
+               var sigTbs sign.SigTBS
                if !*noWhen {
                        when := time.Now().UTC().Truncate(time.Millisecond)
                        sigTbs.When = &when
diff --git a/go/cm/ed25519-blake2b/.gitignore b/go/cm/ed25519-blake2b/.gitignore
deleted file mode 100644 (file)
index ca24282..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-byteorder/
-ed25519/
-edwards25519/
-go.mod
diff --git a/go/cm/ed25519-blake2b/clean b/go/cm/ed25519-blake2b/clean
deleted file mode 100755 (executable)
index 6132ba6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh -e
-
-cd "$(dirname "$(realpath -- "$0")")"
-exec rm -rf byteorder ed25519 edwards25519 go.mod
diff --git a/go/cm/ed25519-blake2b/ed25519-to-blake2b.patch b/go/cm/ed25519-blake2b/ed25519-to-blake2b.patch
deleted file mode 100644 (file)
index 80d2a25..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
---- ed25519/ed25519.go 2024-12-03 10:59:27.811011000 +0300
-+++ ed25519/ed25519.go 2024-12-03 11:07:51.892841000 +0300
-@@ -20,11 +20,12 @@
-       "crypto"
-       "go.cypherpunks.su/keks/cm/ed25519-blake2b/edwards25519"
-       cryptorand "crypto/rand"
--      "crypto/sha512"
-       "crypto/subtle"
-       "errors"
-       "io"
-       "strconv"
-+
-+      "golang.org/x/crypto/blake2b"
- )
- const (
-@@ -81,13 +82,13 @@
- // Sign signs the given message with priv. rand is ignored and can be nil.
- //
--// If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
--// and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
-+// If opts.HashFunc() is [crypto.BLAKE2b_512], the pre-hashed variant Ed25519ph is used
-+// and message is expected to be a BLAKE2b-512 hash, otherwise opts.HashFunc() must
- // be [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
- // passes over messages to be signed.
- //
- // A value of type [Options] can be used as opts, or crypto.Hash(0) or
--// crypto.SHA512 directly to select plain Ed25519 or Ed25519ph, respectively.
-+// crypto.BLAKE2b_512 directly to select plain Ed25519 or Ed25519ph, respectively.
- func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
-       hash := opts.HashFunc()
-       context := ""
-@@ -95,8 +96,8 @@
-               context = opts.Context
-       }
-       switch {
--      case hash == crypto.SHA512: // Ed25519ph
--              if l := len(message); l != sha512.Size {
-+      case hash == crypto.BLAKE2b_512: // Ed25519ph
-+              if l := len(message); l != blake2b.Size {
-                       return nil, errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
-               }
-               if l := len(context); l > 255 {
-@@ -122,7 +123,7 @@
- // Options can be used with [PrivateKey.Sign] or [VerifyWithOptions]
- // to select Ed25519 variants.
- type Options struct {
--      // Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph.
-+      // Hash can be zero for regular Ed25519, or crypto.BLAKE2b_512 for Ed25519ph.
-       Hash crypto.Hash
-       // Context, if not empty, selects Ed25519ctx or provides the context string
-@@ -171,7 +172,7 @@
-               panic("ed25519: bad seed length: " + strconv.Itoa(l))
-       }
--      h := sha512.Sum512(seed)
-+      h := blake2b.Sum512(seed)
-       s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
-       if err != nil {
-               panic("ed25519: internal error: setting scalar failed")
-@@ -213,14 +214,17 @@
-       }
-       seed, publicKey := privateKey[:SeedSize], privateKey[SeedSize:]
--      h := sha512.Sum512(seed)
-+      h := blake2b.Sum512(seed)
-       s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
-       if err != nil {
-               panic("ed25519: internal error: setting scalar failed")
-       }
-       prefix := h[32:]
--      mh := sha512.New()
-+      mh, err := blake2b.New512(nil)
-+      if err != nil {
-+              panic(err)
-+      }
-       if domPrefix != domPrefixPure {
-               mh.Write([]byte(domPrefix))
-               mh.Write([]byte{byte(len(context))})
-@@ -228,7 +232,7 @@
-       }
-       mh.Write(prefix)
-       mh.Write(message)
--      messageDigest := make([]byte, 0, sha512.Size)
-+      messageDigest := make([]byte, 0, blake2b.Size)
-       messageDigest = mh.Sum(messageDigest)
-       r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
-       if err != nil {
-@@ -237,7 +241,10 @@
-       R := (&edwards25519.Point{}).ScalarBaseMult(r)
--      kh := sha512.New()
-+      kh, err := blake2b.New512(nil)
-+      if err != nil {
-+              panic(err)
-+      }
-       if domPrefix != domPrefixPure {
-               kh.Write([]byte(domPrefix))
-               kh.Write([]byte{byte(len(context))})
-@@ -246,7 +253,7 @@
-       kh.Write(R.Bytes())
-       kh.Write(publicKey)
-       kh.Write(message)
--      hramDigest := make([]byte, 0, sha512.Size)
-+      hramDigest := make([]byte, 0, blake2b.Size)
-       hramDigest = kh.Sum(hramDigest)
-       k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
-       if err != nil {
-@@ -272,7 +279,7 @@
- // publicKey. A valid signature is indicated by returning a nil error. It will
- // panic if len(publicKey) is not [PublicKeySize].
- //
--// If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and
-+// If opts.Hash is [crypto.BLAKE2b_512], the pre-hashed variant Ed25519ph is used and
- // message is expected to be a SHA-512 hash, otherwise opts.Hash must be
- // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
- // passes over messages to be signed.
-@@ -281,8 +288,8 @@
- // channels, or if an attacker has control of part of the inputs.
- func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
-       switch {
--      case opts.Hash == crypto.SHA512: // Ed25519ph
--              if l := len(message); l != sha512.Size {
-+      case opts.Hash == crypto.BLAKE2b_512: // Ed25519ph
-+              if l := len(message); l != blake2b.Size {
-                       return errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
-               }
-               if l := len(opts.Context); l > 255 {
-@@ -324,7 +331,10 @@
-               return false
-       }
--      kh := sha512.New()
-+      kh, err := blake2b.New512(nil)
-+      if err != nil {
-+              panic(err)
-+      }
-       if domPrefix != domPrefixPure {
-               kh.Write([]byte(domPrefix))
-               kh.Write([]byte{byte(len(context))})
-@@ -333,7 +343,7 @@
-       kh.Write(sig[:32])
-       kh.Write(publicKey)
-       kh.Write(message)
--      hramDigest := make([]byte, 0, sha512.Size)
-+      hramDigest := make([]byte, 0, blake2b.Size)
-       hramDigest = kh.Sum(hramDigest)
-       k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
-       if err != nil {
diff --git a/go/cm/ed25519-blake2b/mk-from-go b/go/cm/ed25519-blake2b/mk-from-go
deleted file mode 100755 (executable)
index 1c9408c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh -e
-# Unfortunately native crypto/ed25519 is not flexible enough and does
-# not give ability to use different hash in Ed25519.
-# That script copies the library (tested on 1.23.3) and patches it to
-# use BLAKE2b hash.
-
-modname=go.cypherpunks.su/keks/cm/ed25519-blake2b
-go mod init $modname
-dst=$PWD
-cd $(go env GOROOT)/src
-cp -r crypto/ed25519 crypto/internal/edwards25519 internal/byteorder $dst
-cd $dst
-
-cd ed25519
-rm -r testdata
-rm *_test.go
-cd ..
-
-cd edwards25519
-rm doc.go *_test.go
-cd ..
-
-find . -name "*.go" -exec perl -i -npe 's#^(\s+)".*/?internal/(.*)"#$1"'$modname'/$2"#' {} +
-
-cd edwards25519/field/_asm
-go mod edit -module $modname/edwards25519/field/_asm
-perl -i -npe "s#crypto/internal#$modname#" fe_amd64_asm.go
-
-cd $dst
-patch <ed25519-to-blake2b.patch
diff --git a/go/cm/enc/dem.go b/go/cm/enc/dem.go
new file mode 100644 (file)
index 0000000..0165666
--- /dev/null
@@ -0,0 +1,6 @@
+package encrypted
+
+const (
+       BalloonBLAKE2bHKDF = "balloon-blake2b-hkdf"
+       ChaCha20Poly1305   = "chacha20poly1305"
+)
similarity index 100%
rename from go/cm/encrypted/kem.go
rename to go/cm/enc/kem.go
diff --git a/go/cm/enc/magic.go b/go/cm/enc/magic.go
new file mode 100644 (file)
index 0000000..f30fbc7
--- /dev/null
@@ -0,0 +1,5 @@
+package encrypted
+
+import "go.cypherpunks.su/keks"
+
+const Magic = keks.Magic("cm/encrypted")
diff --git a/go/cm/enc/mceliece6960119-x25519/README b/go/cm/enc/mceliece6960119-x25519/README
new file mode 100644 (file)
index 0000000..bfb21d3
--- /dev/null
@@ -0,0 +1,4 @@
+Go/Git is unable to fetch (https://github.com/cloudflare/circl.git)
+pull-request's commit (7dfc396c96830ed3601ace705e1612b9bcc447f9) to
+github.com/cloudflare/circl containing mceliece6960119 implementation
+(https://github.com/cloudflare/circl/pull/378). So copy it here.
similarity index 83%
rename from go/cm/mceliece6960119-x25519/kp.go
rename to go/cm/enc/mceliece6960119-x25519/kp.go
index 35285ee91b75f94c7d323e18ac1e735419a42e6d7fcac4d778350d0b0c809867..57d0a52868a1fa00267d39bcaa4da5d56cdd24bfcc5f0e7978090835cdfe14ff 100644 (file)
@@ -19,15 +19,13 @@ import (
        "crypto/ecdh"
        "crypto/rand"
 
-       "github.com/cloudflare/circl/kem"
-       "github.com/cloudflare/circl/kem/mceliece/mceliece6960119"
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119"
 )
 
 func NewKeypair() (prv, pub []byte, err error) {
-       var pubMcEliece kem.PublicKey
-       var prvMcEliece kem.PrivateKey
-       scheme := mceliece6960119.Scheme()
-       pubMcEliece, prvMcEliece, err = scheme.GenerateKeyPair()
+       var pubMcEliece *mceliece6960119.PublicKey
+       var prvMcEliece *mceliece6960119.PrivateKey
+       pubMcEliece, prvMcEliece, err = mceliece6960119.GenerateKeyPair()
        if err != nil {
                return
        }
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/benes.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/benes.go
new file mode 100644 (file)
index 0000000..fd3e17c
--- /dev/null
@@ -0,0 +1,133 @@
+// Code generated from benes_other.templ.go. DO NOT EDIT.
+
+package mceliece6960119
+
+// Layers of the Beneš network. The required size of `data` and `bits` depends on the value `lgs`.
+func layerIn(data *[2][64]uint64, bits *[64]uint64, lgs int) {
+       s := 1 << lgs
+       index := 0
+       for i := 0; i < 64; i += s * 2 {
+               for j := i; j < i+s; j++ {
+                       d := data[0][j+0] ^ data[0][j+s]
+                       d &= bits[index]
+                       data[0][j+0] ^= d
+                       data[0][j+s] ^= d
+                       index += 1
+
+                       d = data[1][j+0] ^ data[1][j+s]
+                       d &= bits[index]
+                       data[1][j+0] ^= d
+                       data[1][j+s] ^= d
+                       index += 1
+               }
+       }
+}
+
+// Exterior layers of the Beneš network. The length of `bits` depends on the value of `lgs`.
+// Note that this implementation is quite different from the C implementation.
+// However, it does make sense. Whereas the C implementation uses pointer arithmetic to access
+// the entire array `data`, this implementation always considers `data` as two-dimensional array.
+// The C implementation uses 128 as upper bound (because the array contains 128 elements),
+// but this implementation has 64 elements per subarray and needs case distinctions at different places.
+func layerEx(data *[2][64]uint64, bits *[64]uint64, lgs int) {
+       data0Idx := 0
+       data1Idx := 32
+       s := 1 << lgs
+       if s == 64 {
+               for j := 0; j < 64; j++ {
+                       d := data[0][j+0] ^ data[1][j]
+                       d &= bits[data0Idx]
+                       data0Idx += 1
+                       data[0][j+0] ^= d
+                       data[1][j] ^= d
+               }
+       } else {
+               for i := 0; i < 64; i += s * 2 {
+                       for j := i; j < i+s; j++ {
+                               d := data[0][j+0] ^ data[0][j+s]
+                               d &= bits[data0Idx]
+                               data0Idx += 1
+
+                               data[0][j+0] ^= d
+                               data[0][j+s] ^= d
+
+                               // data[1] computations
+                               d = data[1][j+0] ^ data[1][j+s]
+                               d &= bits[data1Idx]
+                               data1Idx += 1
+
+                               data[1][j+0] ^= d
+                               data[1][j+s] ^= d
+                       }
+               }
+       }
+}
+
+// Apply Beneš network in-place to array `r` based on configuration `bits`.
+// Here, `r` is a sequence of bits to be permuted.
+// `bits` defines the condition bits configuring the Beneš network and
+// Note that this differs from the C implementation, missing the `rev` parameter.
+// This is because `rev` is not used throughout the entire codebase.
+func applyBenes(r *[1024]byte, bits *[condBytes]byte) {
+       rIntV := [2][64]uint64{}
+       rIntH := [2][64]uint64{}
+       bIntV := [64]uint64{}
+       bIntH := [64]uint64{}
+       bitsPtr := bits[:]
+
+       for i := 0; i < 64; i++ {
+               rIntV[0][i] = load8(r[i*16:])
+               rIntV[1][i] = load8(r[i*16+8:])
+       }
+
+       transpose64x64(&rIntH[0], &rIntV[0])
+       transpose64x64(&rIntH[1], &rIntV[1])
+
+       for iter := 0; iter <= 6; iter++ {
+               for i := 0; i < 64; i++ {
+                       bIntV[i] = load8(bitsPtr)
+                       bitsPtr = bitsPtr[8:]
+               }
+               transpose64x64(&bIntH, &bIntV)
+               layerEx(&rIntH, &bIntH, iter)
+       }
+
+       transpose64x64(&rIntV[0], &rIntH[0])
+       transpose64x64(&rIntV[1], &rIntH[1])
+
+       for iter := 0; iter <= 5; iter++ {
+               for i := 0; i < 64; i++ {
+                       bIntV[i] = load8(bitsPtr)
+                       bitsPtr = bitsPtr[8:]
+               }
+               layerIn(&rIntV, &bIntV, iter)
+       }
+
+       for iter := 4; iter >= 0; iter-- {
+               for i := 0; i < 64; i++ {
+                       bIntV[i] = load8(bitsPtr)
+                       bitsPtr = bitsPtr[8:]
+               }
+               layerIn(&rIntV, &bIntV, iter)
+       }
+
+       transpose64x64(&rIntH[0], &rIntV[0])
+       transpose64x64(&rIntH[1], &rIntV[1])
+
+       for iter := 6; iter >= 0; iter-- {
+               for i := 0; i < 64; i++ {
+                       bIntV[i] = load8(bitsPtr)
+                       bitsPtr = bitsPtr[8:]
+               }
+               transpose64x64(&bIntH, &bIntV)
+               layerEx(&rIntH, &bIntH, iter)
+       }
+
+       transpose64x64(&rIntV[0], &rIntH[0])
+       transpose64x64(&rIntV[1], &rIntH[1])
+
+       for i := 0; i < 64; i++ {
+               store8(r[i*16+0:], rIntV[0][i])
+               store8(r[i*16+8:], rIntV[1][i])
+       }
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/fft.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/fft.go
new file mode 100644 (file)
index 0000000..270331c
--- /dev/null
@@ -0,0 +1,208 @@
+// Code generated from fft_other.templ.go. DO NOT EDIT.
+
+// The following code is translated from the C `vec` Additional Implementation
+// from the NIST round 4 submission package.
+
+package mceliece6960119
+
+import "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/internal"
+
+func fft(out *[exponent][gfBits]uint64, in *[2][gfBits]uint64) {
+       radixConversions(in)
+       butterflies(out, in)
+}
+
+func radixConversions(in *[2][gfBits]uint64) {
+       for j := 0; j <= 5; j++ {
+               for i := 0; i < gfBits; i++ {
+                       in[1][i] ^= in[1][i] >> 32
+                       in[0][i] ^= in[1][i] << 32
+               }
+
+               for i := 0; i < gfBits; i++ {
+                       for k := 4; k >= j; k-- {
+                               in[0][i] ^= (in[0][i] & internal.RadixConversionsMask[k][0]) >> (1 << k)
+                               in[0][i] ^= (in[0][i] & internal.RadixConversionsMask[k][1]) >> (1 << k)
+                               in[1][i] ^= (in[1][i] & internal.RadixConversionsMask[k][0]) >> (1 << k)
+                               in[1][i] ^= (in[1][i] & internal.RadixConversionsMask[k][1]) >> (1 << k)
+                       }
+               }
+
+               if j < 5 {
+                       vecMul(&in[0], &in[0], &internal.RadixConversionsS[j][0])
+                       vecMul(&in[1], &in[1], &internal.RadixConversionsS[j][1])
+               }
+       }
+}
+
+func butterflies(out *[exponent][gfBits]uint64, in *[2][gfBits]uint64) {
+       tmp := [gfBits]uint64{}
+       pre := [8][gfBits]uint64{}
+       buf := [128]uint64{}
+       constsPtr := 2
+       for i := 0; i < 7; i++ {
+               for j := 0; j < gfBits; j++ {
+                       pre[i][j] = uint64(internal.ButterfliesBeta[i]>>j) & 1
+                       pre[i][j] = -pre[i][j]
+               }
+
+               vecMul(&pre[i], &in[1], &pre[i])
+       }
+       for i := 0; i < gfBits; i++ {
+               buf[0] = in[0][i]
+
+               buf[1] = buf[0] ^ pre[0][i]
+               buf[32] = in[0][i] ^ pre[5][i]
+               buf[3] = buf[1] ^ pre[1][i]
+               buf[96] = buf[32] ^ pre[6][i]
+               buf[97] = buf[96] ^ pre[0][i]
+               buf[2] = in[0][i] ^ pre[1][i]
+               buf[99] = buf[97] ^ pre[1][i]
+               buf[6] = buf[2] ^ pre[2][i]
+               buf[98] = buf[99] ^ pre[0][i]
+               buf[7] = buf[6] ^ pre[0][i]
+               buf[102] = buf[98] ^ pre[2][i]
+               buf[5] = buf[7] ^ pre[1][i]
+               buf[103] = buf[102] ^ pre[0][i]
+               buf[101] = buf[103] ^ pre[1][i]
+               buf[4] = in[0][i] ^ pre[2][i]
+               buf[100] = buf[101] ^ pre[0][i]
+               buf[12] = buf[4] ^ pre[3][i]
+               buf[108] = buf[100] ^ pre[3][i]
+               buf[13] = buf[12] ^ pre[0][i]
+               buf[109] = buf[108] ^ pre[0][i]
+               buf[15] = buf[13] ^ pre[1][i]
+               buf[111] = buf[109] ^ pre[1][i]
+               buf[14] = buf[15] ^ pre[0][i]
+               buf[110] = buf[111] ^ pre[0][i]
+               buf[10] = buf[14] ^ pre[2][i]
+               buf[106] = buf[110] ^ pre[2][i]
+               buf[11] = buf[10] ^ pre[0][i]
+               buf[107] = buf[106] ^ pre[0][i]
+               buf[9] = buf[11] ^ pre[1][i]
+               buf[105] = buf[107] ^ pre[1][i]
+               buf[104] = buf[105] ^ pre[0][i]
+               buf[8] = in[0][i] ^ pre[3][i]
+               buf[120] = buf[104] ^ pre[4][i]
+               buf[24] = buf[8] ^ pre[4][i]
+               buf[121] = buf[120] ^ pre[0][i]
+               buf[25] = buf[24] ^ pre[0][i]
+               buf[123] = buf[121] ^ pre[1][i]
+               buf[27] = buf[25] ^ pre[1][i]
+               buf[122] = buf[123] ^ pre[0][i]
+               buf[26] = buf[27] ^ pre[0][i]
+               buf[126] = buf[122] ^ pre[2][i]
+               buf[30] = buf[26] ^ pre[2][i]
+               buf[127] = buf[126] ^ pre[0][i]
+               buf[31] = buf[30] ^ pre[0][i]
+               buf[125] = buf[127] ^ pre[1][i]
+               buf[29] = buf[31] ^ pre[1][i]
+               buf[124] = buf[125] ^ pre[0][i]
+               buf[28] = buf[29] ^ pre[0][i]
+               buf[116] = buf[124] ^ pre[3][i]
+               buf[20] = buf[28] ^ pre[3][i]
+               buf[117] = buf[116] ^ pre[0][i]
+               buf[21] = buf[20] ^ pre[0][i]
+               buf[119] = buf[117] ^ pre[1][i]
+               buf[23] = buf[21] ^ pre[1][i]
+               buf[118] = buf[119] ^ pre[0][i]
+               buf[22] = buf[23] ^ pre[0][i]
+               buf[114] = buf[118] ^ pre[2][i]
+               buf[18] = buf[22] ^ pre[2][i]
+               buf[115] = buf[114] ^ pre[0][i]
+               buf[19] = buf[18] ^ pre[0][i]
+               buf[113] = buf[115] ^ pre[1][i]
+               buf[17] = buf[19] ^ pre[1][i]
+               buf[112] = buf[113] ^ pre[0][i]
+               buf[80] = buf[112] ^ pre[5][i]
+               buf[16] = in[0][i] ^ pre[4][i]
+               buf[81] = buf[80] ^ pre[0][i]
+               buf[48] = buf[16] ^ pre[5][i]
+               buf[83] = buf[81] ^ pre[1][i]
+               buf[49] = buf[48] ^ pre[0][i]
+               buf[82] = buf[83] ^ pre[0][i]
+               buf[51] = buf[49] ^ pre[1][i]
+               buf[86] = buf[82] ^ pre[2][i]
+               buf[50] = buf[51] ^ pre[0][i]
+               buf[87] = buf[86] ^ pre[0][i]
+               buf[54] = buf[50] ^ pre[2][i]
+               buf[85] = buf[87] ^ pre[1][i]
+               buf[55] = buf[54] ^ pre[0][i]
+               buf[84] = buf[85] ^ pre[0][i]
+               buf[53] = buf[55] ^ pre[1][i]
+               buf[92] = buf[84] ^ pre[3][i]
+               buf[52] = buf[53] ^ pre[0][i]
+               buf[93] = buf[92] ^ pre[0][i]
+               buf[60] = buf[52] ^ pre[3][i]
+               buf[95] = buf[93] ^ pre[1][i]
+               buf[61] = buf[60] ^ pre[0][i]
+               buf[94] = buf[95] ^ pre[0][i]
+               buf[63] = buf[61] ^ pre[1][i]
+               buf[90] = buf[94] ^ pre[2][i]
+               buf[62] = buf[63] ^ pre[0][i]
+               buf[91] = buf[90] ^ pre[0][i]
+               buf[58] = buf[62] ^ pre[2][i]
+               buf[89] = buf[91] ^ pre[1][i]
+               buf[59] = buf[58] ^ pre[0][i]
+               buf[88] = buf[89] ^ pre[0][i]
+               buf[57] = buf[59] ^ pre[1][i]
+               buf[72] = buf[88] ^ pre[4][i]
+               buf[56] = buf[57] ^ pre[0][i]
+               buf[73] = buf[72] ^ pre[0][i]
+               buf[40] = buf[56] ^ pre[4][i]
+               buf[75] = buf[73] ^ pre[1][i]
+               buf[41] = buf[40] ^ pre[0][i]
+               buf[74] = buf[75] ^ pre[0][i]
+               buf[43] = buf[41] ^ pre[1][i]
+               buf[78] = buf[74] ^ pre[2][i]
+               buf[42] = buf[43] ^ pre[0][i]
+               buf[79] = buf[78] ^ pre[0][i]
+               buf[46] = buf[42] ^ pre[2][i]
+               buf[77] = buf[79] ^ pre[1][i]
+               buf[47] = buf[46] ^ pre[0][i]
+               buf[76] = buf[77] ^ pre[0][i]
+               buf[45] = buf[47] ^ pre[1][i]
+               buf[68] = buf[76] ^ pre[3][i]
+               buf[44] = buf[45] ^ pre[0][i]
+               buf[69] = buf[68] ^ pre[0][i]
+               buf[36] = buf[44] ^ pre[3][i]
+               buf[71] = buf[69] ^ pre[1][i]
+               buf[37] = buf[36] ^ pre[0][i]
+               buf[70] = buf[71] ^ pre[0][i]
+               buf[39] = buf[37] ^ pre[1][i]
+               buf[66] = buf[70] ^ pre[2][i]
+               buf[38] = buf[39] ^ pre[0][i]
+               buf[67] = buf[66] ^ pre[0][i]
+               buf[34] = buf[38] ^ pre[2][i]
+               buf[65] = buf[67] ^ pre[1][i]
+               buf[35] = buf[34] ^ pre[0][i]
+               buf[33] = buf[35] ^ pre[1][i]
+               buf[64] = in[0][i] ^ pre[6][i]
+
+               transpose64x64((*[64]uint64)(buf[:64]), (*[64]uint64)(buf[:64]))
+               transpose64x64((*[64]uint64)(buf[64:]), (*[64]uint64)(buf[64:]))
+
+               for j := 0; j < 128; j++ {
+                       out[internal.ButterfliesReversal[j]][i] = buf[j]
+               }
+       }
+
+       for i := 1; i <= 6; i++ {
+               s := 1 << i
+
+               for j := 0; j < 128; j += 2 * s {
+                       for k := j; k < j+s; k++ {
+                               vecMul(&tmp, &out[k+s], &internal.ButterfliesConst[constsPtr+(k-j)])
+
+                               for b := 0; b < gfBits; b++ {
+                                       out[k][b] ^= tmp[b]
+                               }
+                               for b := 0; b < gfBits; b++ {
+                                       out[k+s][b] ^= out[k][b]
+                               }
+                       }
+               }
+
+               constsPtr += 1 << i
+       }
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/controlbits.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/controlbits.go
new file mode 100644 (file)
index 0000000..d49a7a4
--- /dev/null
@@ -0,0 +1,248 @@
+// This file is for implementing the Nassimi-Sahni algorithm
+// See David Nassimi, Sartaj Sahni "Parallel algorithms to set up the Benes permutationnetwork"
+// See also https://cr.yp.to/papers/controlbits-20200923.pdf
+
+package internal
+
+import (
+       "unsafe"
+)
+
+// layer implements one layer of the Beneš network.
+// It permutes elements `p` according to control bits `cb` in-place.
+// Thus, one layer of the Beneš network is created and if some control bits are set
+// the corresponding transposition is applied. Parameter `s` equals `n.len()` and
+// `s` configures `stride-2^s` conditional swaps.
+func layer(p []int16, cb []byte, s, n int) {
+       stride := 1 << s
+       index := 0
+       for i := int(0); i < n; i += stride * 2 {
+               for j := int(0); j < stride; j++ {
+                       d := p[i+j] ^ p[i+j+stride]
+                       m := int16(cb[index>>3]>>(index&7)) & 1
+                       m = -m
+                       d &= m
+                       p[i+j] ^= d
+                       p[i+j+stride] ^= d
+                       index++
+               }
+       }
+}
+
+// cbRecursion implements a recursion step of controlbitsfrompermutation.
+// Pick `w ∈ {1, 2, …, 14}. Let `n = 2^w`.
+// `out` must be a reference to a slice with `((2*w-1)*(1<<(w-1))+7)/8` or more bytes.
+// It must zero-initialized before the first recursive call.
+// `step` is initialized with 0 and doubles in each recursion step.
+// `pi_offset` is an offset within temp slice ref (or aux in the first recursive call).
+// `temp` is an intermediate reference to a slice used for recursive computation and
+// temporarily stores values. It must be able to carry at least 2・n elements.
+// `aux` is an auxiliary reference to a slice. It points to the elements to be permuted.
+// After the first recursive iterations, the elements are stored in `temp` and thus `aux`
+// won't be read anymore. The first `n/2` elements are read.
+// nolint:funlen
+func cbRecursion(out []byte, pos, step int, pi []int16, w, n int32, temp []int32) {
+       A := temp
+       B := temp[n:]
+       if w == 1 {
+               out[pos>>3] ^= byte(pi[0] << (pos & 7))
+               return
+       }
+
+       for x := int32(0); x < n; x++ {
+               A[x] = (int32(pi[x]^1) << 16) | int32(pi[x^1])
+       }
+       int32Sort(A, n) // A = (id<<16)+pibar
+
+       for x := int32(0); x < n; x++ {
+               Ax := A[x]
+               px := Ax & 0xffff
+               cx := px
+               if x < cx {
+                       cx = x
+               }
+               B[x] = (px << 16) | cx
+       }
+       // B = (p<<16)+c
+
+       for x := int32(0); x < n; x++ {
+               A[x] = (A[x] << 16) | x
+       }
+       int32Sort(A, n) // A = (id<<16)+pibar^-1
+
+       for x := int32(0); x < n; x++ {
+               // A = (pibar^(-1)<<16)+pibar
+               A[x] = (A[x] << 16) + (B[x] >> 16)
+       }
+       int32Sort(A, n) // A = (id<<16)+pibar^2
+
+       if w <= 10 {
+               for x := int32(0); x < n; x++ {
+                       B[x] = ((A[x] & 0xffff) << 10) | (B[x] & 0x3ff)
+               }
+
+               for i := int32(1); i < w-1; i++ {
+                       /* B = (p<<10)+c */
+
+                       for x := int32(0); x < n; x++ {
+                               A[x] = ((B[x] & ^0x3ff) << 6) | x /* A = (p<<16)+id */
+                       }
+                       int32Sort(A, n) /* A = (id<<16)+p^{-1} */
+
+                       for x := int32(0); x < n; x++ {
+                               A[x] = (A[x] << 20) | B[x] /* A = (p^{-1}<<20)+(p<<10)+c */
+                       }
+                       int32Sort(A, n) /* A = (id<<20)+(pp<<10)+cp */
+
+                       for x := int32(0); x < n; x++ {
+                               ppcpx := A[x] & 0xfffff
+                               ppcx := (A[x] & 0xffc00) | (B[x] & 0x3ff)
+                               if ppcpx < ppcx {
+                                       ppcx = ppcpx
+                               }
+                               B[x] = ppcx
+                       }
+               }
+
+               for x := int32(0); x < n; x++ {
+                       B[x] &= 0x3ff
+               }
+       } else {
+               for x := int32(0); x < n; x++ {
+                       B[x] = (A[x] << 16) | (B[x] & 0xffff)
+               }
+
+               for i := int32(1); i < w-1; i++ {
+                       /* B = (p<<16)+c */
+
+                       for x := int32(0); x < n; x++ {
+                               A[x] = (B[x] &^ 0xffff) | x
+                       }
+                       int32Sort(A, n) /* A = (id<<16)+p^(-1) */
+
+                       for x := int32(0); x < n; x++ {
+                               A[x] = (A[x] << 16) | (B[x] & 0xffff)
+                       }
+                       /* A = p^(-1)<<16+c */
+
+                       if i < w-2 {
+                               for x := int32(0); x < n; x++ {
+                                       B[x] = (A[x] & ^0xffff) | (B[x] >> 16)
+                               }
+                               /* B = (p^(-1)<<16)+p */
+                               int32Sort(B, n) /* B = (id<<16)+p^(-2) */
+                               for x := int32(0); x < n; x++ {
+                                       B[x] = (B[x] << 16) | (A[x] & 0xffff)
+                               }
+                               /* B = (p^(-2)<<16)+c */
+                       }
+
+                       int32Sort(A, n)
+                       /* A = id<<16+cp */
+                       for x := int32(0); x < n; x++ {
+                               cpx := (B[x] & ^0xffff) | (A[x] & 0xffff)
+                               if cpx < B[x] {
+                                       B[x] = cpx
+                               }
+                       }
+               }
+
+               for x := int32(0); x < n; x++ {
+                       B[x] &= 0xffff
+               }
+       }
+
+       for x := int32(0); x < n; x++ {
+               A[x] = (int32(pi[x]) << 16) + x
+       }
+       int32Sort(A, n) /* A = (id<<16)+pi^(-1) */
+
+       for j := int32(0); j < n/2; j++ {
+               x := 2 * j
+               fj := B[x] & 1 /* f[j] */
+               Fx := x + fj   /* F[x] */
+               Fx1 := Fx ^ 1  /* F[x+1] */
+
+               out[pos>>3] ^= byte(fj << (pos & 7))
+               pos += step
+
+               B[x] = (A[x] << 16) | Fx
+               B[x+1] = (A[x+1] << 16) | Fx1
+       }
+       /* B = (pi^(-1)<<16)+F */
+
+       int32Sort(B, n) /* B = (id<<16)+F(pi) */
+
+       pos += int(2*w-3) * step * int(n/2)
+
+       for k := int32(0); k < n/2; k++ {
+               y := 2 * k
+               lk := B[y] & 1 /* l[k] */
+               Ly := y + lk   /* L[y] */
+               Ly1 := Ly ^ 1  /* L[y+1] */
+
+               out[pos>>3] ^= byte(lk << (pos & 7))
+               pos += step
+
+               A[y] = (Ly << 16) | (B[y] & 0xffff)
+               A[y+1] = (Ly1 << 16) | (B[y+1] & 0xffff)
+       }
+       /* A = (L<<16)+F(pi) */
+
+       int32Sort(A, n) /* A = (id<<16)+F(pi(L)) = (id<<16)+M */
+
+       pos -= int(2*w-2) * step * int(n/2)
+
+       p := (*int16)(unsafe.Pointer(&temp[n+n/4]))
+       q := unsafe.Slice(p, n) // q can start anywhere between temp+n and temp+n/2
+       for j := int32(0); j < n/2; j++ {
+               q[j] = int16(A[2*j]&0xffff) >> 1
+               q[j+n/2] = int16(A[2*j+1]&0xffff) >> 1
+       }
+
+       cbRecursion(out, pos, step*2, q, w-1, n/2, temp)
+       cbRecursion(out, pos+step, step*2, q[n/2:], w-1, n/2, temp)
+}
+
+// ControlBitsFromPermutation computes control bits
+// parameters: 1 <= w <= 14; n = 2^w
+// input: permutation pi of {0,1,...,n-1}
+// output: (2m-1)n/2 control bits at positions 0,1,...
+// output position pos is by definition 1&(out[pos/8]>>(pos&7))
+func ControlBitsFromPermutation(out []byte, pi []int16, w, n int32) {
+       temp := make([]int32, 2*n)
+       piTest := make([]int16, n)
+       var ptr []byte
+       for {
+               for i := 0; i < int(((2*w-1)*n/2)+7)/8; i++ {
+                       out[i] = 0
+               }
+
+               cbRecursion(out, 0, 1, pi[:], w, n, temp)
+               // check for correctness
+
+               for i := int32(0); i < n; i++ {
+                       piTest[i] = int16(i)
+               }
+
+               ptr = out
+               for i := 0; i < int(w); i++ {
+                       layer(piTest, ptr, i, int(n))
+                       ptr = ptr[n>>4:]
+               }
+
+               for i := int(w - 2); i >= 0; i-- {
+                       layer(piTest, ptr, i, int(n))
+                       ptr = ptr[n>>4:]
+               }
+
+               diff := int16(0)
+               for i := int32(0); i < n; i++ {
+                       diff |= pi[i] ^ piTest[i]
+               }
+
+               if diff == 0 {
+                       break
+               }
+       }
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/djbsort.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/djbsort.go
new file mode 100644 (file)
index 0000000..72210b8
--- /dev/null
@@ -0,0 +1,92 @@
+package internal
+
+// Returns (min(a, b), max(a, b)), executes in constant time
+func minMaxI32(a, b *int32) {
+       ab := *b ^ *a
+       c := *b - *a
+       c ^= ab & (c ^ *b)
+       c >>= 31
+       c &= ab
+       *a ^= c
+       *b ^= c
+}
+
+// Returns (min(a, b), max(a, b)), executes in constant time
+//
+// This differs from the C implementation, because the C implementation
+// only works for 63-bit integers.
+//
+// Instead this implementation is based on
+// “side-channel effective overflow check of variable c”
+// from the book “Hacker's Delight” 2–13 Overflow Detection,
+// Section Unsigned Add/Subtract p. 40
+func minMaxU64(a, b *uint64) {
+       c := (^*b & *a) | ((^*b | *a) & (*b - *a))
+       c = -(c >> 63)
+       c &= *a ^ *b
+       *a ^= c
+       *b ^= c
+}
+
+// Reference: [djbsort](https://sorting.cr.yp.to/).
+func int32Sort(x []int32, n int32) {
+       if n < 2 {
+               return
+       }
+       top := int32(1)
+       for top < n-top {
+               top += top
+       }
+       for p := top; p > 0; p >>= 1 {
+               for i := int32(0); i < n-p; i++ {
+                       if (i & p) == 0 {
+                               minMaxI32(&x[i], &x[i+p])
+                       }
+               }
+
+               i := int32(0)
+               for q := top; q > p; q >>= 1 {
+                       for ; i < n-q; i++ {
+                               if (i & p) == 0 {
+                                       a := x[i+p]
+                                       for r := q; r > p; r >>= 1 {
+                                               minMaxI32(&a, &x[i+r])
+                                       }
+                                       x[i+p] = a
+                               }
+                       }
+               }
+       }
+}
+
+// UInt64Sort sorts a slice of uint64
+// Reference: [djbsort](https://sorting.cr.yp.to/).
+func UInt64Sort(x []uint64, n int) {
+       if n < 2 {
+               return
+       }
+       top := 1
+       for top < n-top {
+               top += top
+       }
+       for p := top; p > 0; p >>= 1 {
+               for i := 0; i < n-p; i++ {
+                       if (i & p) == 0 {
+                               minMaxU64(&x[i], &x[i+p])
+                       }
+               }
+
+               i := 0
+               for q := top; q > p; q >>= 1 {
+                       for ; i < n-q; i++ {
+                               if (i & p) == 0 {
+                                       a := x[i+p]
+                                       for r := q; r > p; r >>= 1 {
+                                               minMaxU64(&a, &x[i+r])
+                                       }
+                                       x[i+p] = a
+                               }
+                       }
+               }
+       }
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/fft_const.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/fft_const.go
new file mode 100644 (file)
index 0000000..95eba56
--- /dev/null
@@ -0,0 +1,3096 @@
+package internal
+
+import (
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e12"
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e13"
+)
+
+var ButterfliesReversal4096 = [64]byte{
+       0, 32, 16, 48, 8, 40, 24, 56,
+       4, 36, 20, 52, 12, 44, 28, 60,
+       2, 34, 18, 50, 10, 42, 26, 58,
+       6, 38, 22, 54, 14, 46, 30, 62,
+       1, 33, 17, 49, 9, 41, 25, 57,
+       5, 37, 21, 53, 13, 45, 29, 61,
+       3, 35, 19, 51, 11, 43, 27, 59,
+       7, 39, 23, 55, 15, 47, 31, 63,
+}
+
+var ButterfliesReversal = [128]byte{
+       0, 64, 32, 96, 16, 80, 48, 112,
+       8, 72, 40, 104, 24, 88, 56, 120,
+       4, 68, 36, 100, 20, 84, 52, 116,
+       12, 76, 44, 108, 28, 92, 60, 124,
+       2, 66, 34, 98, 18, 82, 50, 114,
+       10, 74, 42, 106, 26, 90, 58, 122,
+       6, 70, 38, 102, 22, 86, 54, 118,
+       14, 78, 46, 110, 30, 94, 62, 126,
+       1, 65, 33, 97, 17, 81, 49, 113,
+       9, 73, 41, 105, 25, 89, 57, 121,
+       5, 69, 37, 101, 21, 85, 53, 117,
+       13, 77, 45, 109, 29, 93, 61, 125,
+       3, 67, 35, 99, 19, 83, 51, 115,
+       11, 75, 43, 107, 27, 91, 59, 123,
+       7, 71, 39, 103, 23, 87, 55, 119,
+       15, 79, 47, 111, 31, 95, 63, 127,
+}
+
+var ButterfliesBeta = [7]uint16{2522, 7827, 7801, 8035, 6897, 8167, 3476}
+
+var RadixConversionsMask = [5][2]uint64{
+       {0x8888888888888888, 0x4444444444444444},
+       {0xC0C0C0C0C0C0C0C0, 0x3030303030303030},
+       {0xF000F000F000F000, 0x0F000F000F000F00},
+       {0xFF000000FF000000, 0x00FF000000FF0000},
+       {0xFFFF000000000000, 0x0000FFFF00000000},
+}
+
+var ButterfliesConst = [128][gf2e13.Bits]uint64{
+       {
+               0x6969969669699696,
+               0x9966669966999966,
+               0x9966669966999966,
+               0xFF0000FF00FFFF00,
+               0xCC3333CCCC3333CC,
+               0x9966669966999966,
+               0x6666666666666666,
+               0xA55AA55AA55AA55A,
+               0xCCCC33333333CCCC,
+               0x5A5A5A5A5A5A5A5A,
+               0x55AAAA55AA5555AA,
+               0x0FF0F00FF00F0FF0,
+               0x5AA55AA5A55AA55A,
+       },
+       {
+               0x6969969669699696,
+               0x9966669966999966,
+               0x9966669966999966,
+               0xFF0000FF00FFFF00,
+               0xCC3333CCCC3333CC,
+               0x9966669966999966,
+               0x6666666666666666,
+               0xA55AA55AA55AA55A,
+               0xCCCC33333333CCCC,
+               0x5A5A5A5A5A5A5A5A,
+               0x55AAAA55AA5555AA,
+               0x0FF0F00FF00F0FF0,
+               0x5AA55AA5A55AA55A,
+       },
+       {
+               0xA55A5AA55AA5A55A,
+               0x6969696996969696,
+               0x5AA55AA5A55AA55A,
+               0x9999999966666666,
+               0x3C3CC3C3C3C33C3C,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xCC33CC3333CC33CC,
+               0x0000000000000000,
+               0x3C3C3C3C3C3C3C3C,
+               0xAA5555AAAA5555AA,
+               0xC33C3CC33CC3C33C,
+               0x00FFFF0000FFFF00,
+       },
+       {
+               0xA55A5AA55AA5A55A,
+               0x6969696996969696,
+               0x5AA55AA5A55AA55A,
+               0x6666666699999999,
+               0xC3C33C3C3C3CC3C3,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x33CC33CCCC33CC33,
+               0x0000000000000000,
+               0x3C3C3C3C3C3C3C3C,
+               0xAA5555AAAA5555AA,
+               0xC33C3CC33CC3C33C,
+               0xFF0000FFFF0000FF,
+       },
+       {
+               0xFFFFFFFF00000000,
+               0xA5A5A5A55A5A5A5A,
+               0x0FF0F00FF00F0FF0,
+               0x9669966969966996,
+               0x0000FFFFFFFF0000,
+               0x33333333CCCCCCCC,
+               0xA55A5AA55AA5A55A,
+               0x00FFFF0000FFFF00,
+               0x0000000000000000,
+               0xC33CC33CC33CC33C,
+               0x0F0FF0F00F0FF0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAA55555555AAAA,
+       },
+       {
+               0xFFFFFFFF00000000,
+               0xA5A5A5A55A5A5A5A,
+               0x0FF0F00FF00F0FF0,
+               0x6996699696699669,
+               0xFFFF00000000FFFF,
+               0x33333333CCCCCCCC,
+               0x5AA5A55AA55A5AA5,
+               0xFF0000FFFF0000FF,
+               0xFFFFFFFFFFFFFFFF,
+               0xC33CC33CC33CC33C,
+               0x0F0FF0F00F0FF0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0x5555AAAAAAAA5555,
+       },
+       {
+               0xFFFFFFFF00000000,
+               0x5A5A5A5AA5A5A5A5,
+               0xF00F0FF00FF0F00F,
+               0x6996699696699669,
+               0x0000FFFFFFFF0000,
+               0x33333333CCCCCCCC,
+               0x5AA5A55AA55A5AA5,
+               0xFF0000FFFF0000FF,
+               0xFFFFFFFFFFFFFFFF,
+               0xC33CC33CC33CC33C,
+               0x0F0FF0F00F0FF0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAA55555555AAAA,
+       },
+       {
+               0xFFFFFFFF00000000,
+               0x5A5A5A5AA5A5A5A5,
+               0xF00F0FF00FF0F00F,
+               0x9669966969966996,
+               0xFFFF00000000FFFF,
+               0x33333333CCCCCCCC,
+               0xA55A5AA55AA5A55A,
+               0x00FFFF0000FFFF00,
+               0x0000000000000000,
+               0xC33CC33CC33CC33C,
+               0x0F0FF0F00F0FF0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0x5555AAAAAAAA5555,
+       },
+       {
+               0xC33C3CC33CC3C33C,
+               0x9966669966999966,
+               0x9966996699669966,
+               0x6969969669699696,
+               0xAA55AA5555AA55AA,
+               0x9966996699669966,
+               0x5AA5A55A5AA5A55A,
+               0xC3C3C3C33C3C3C3C,
+               0x3CC33CC3C33CC33C,
+               0x3333CCCC3333CCCC,
+               0x9999999966666666,
+               0xC33CC33CC33CC33C,
+               0x6666999999996666,
+       },
+       {
+               0x3CC3C33CC33C3CC3,
+               0x6699996699666699,
+               0x6699669966996699,
+               0x6969969669699696,
+               0xAA55AA5555AA55AA,
+               0x9966996699669966,
+               0xA55A5AA5A55A5AA5,
+               0xC3C3C3C33C3C3C3C,
+               0x3CC33CC3C33CC33C,
+               0x3333CCCC3333CCCC,
+               0x6666666699999999,
+               0x3CC33CC33CC33CC3,
+               0x9999666666669999,
+       },
+       {
+               0xC33C3CC33CC3C33C,
+               0x9966669966999966,
+               0x6699669966996699,
+               0x6969969669699696,
+               0xAA55AA5555AA55AA,
+               0x6699669966996699,
+               0x5AA5A55A5AA5A55A,
+               0x3C3C3C3CC3C3C3C3,
+               0xC33CC33C3CC33CC3,
+               0xCCCC3333CCCC3333,
+               0x6666666699999999,
+               0xC33CC33CC33CC33C,
+               0x9999666666669999,
+       },
+       {
+               0x3CC3C33CC33C3CC3,
+               0x6699996699666699,
+               0x9966996699669966,
+               0x6969969669699696,
+               0xAA55AA5555AA55AA,
+               0x6699669966996699,
+               0xA55A5AA5A55A5AA5,
+               0x3C3C3C3CC3C3C3C3,
+               0xC33CC33C3CC33CC3,
+               0xCCCC3333CCCC3333,
+               0x9999999966666666,
+               0x3CC33CC33CC33CC3,
+               0x6666999999996666,
+       },
+       {
+               0xC33C3CC33CC3C33C,
+               0x6699996699666699,
+               0x6699669966996699,
+               0x6969969669699696,
+               0x55AA55AAAA55AA55,
+               0x9966996699669966,
+               0x5AA5A55A5AA5A55A,
+               0xC3C3C3C33C3C3C3C,
+               0xC33CC33C3CC33CC3,
+               0x3333CCCC3333CCCC,
+               0x9999999966666666,
+               0xC33CC33CC33CC33C,
+               0x6666999999996666,
+       },
+       {
+               0x3CC3C33CC33C3CC3,
+               0x9966669966999966,
+               0x9966996699669966,
+               0x6969969669699696,
+               0x55AA55AAAA55AA55,
+               0x9966996699669966,
+               0xA55A5AA5A55A5AA5,
+               0xC3C3C3C33C3C3C3C,
+               0xC33CC33C3CC33CC3,
+               0x3333CCCC3333CCCC,
+               0x6666666699999999,
+               0x3CC33CC33CC33CC3,
+               0x9999666666669999,
+       },
+       {
+               0xC33C3CC33CC3C33C,
+               0x6699996699666699,
+               0x9966996699669966,
+               0x6969969669699696,
+               0x55AA55AAAA55AA55,
+               0x6699669966996699,
+               0x5AA5A55A5AA5A55A,
+               0x3C3C3C3CC3C3C3C3,
+               0x3CC33CC3C33CC33C,
+               0xCCCC3333CCCC3333,
+               0x6666666699999999,
+               0xC33CC33CC33CC33C,
+               0x9999666666669999,
+       },
+       {
+               0x3CC3C33CC33C3CC3,
+               0x9966669966999966,
+               0x6699669966996699,
+               0x6969969669699696,
+               0x55AA55AAAA55AA55,
+               0x6699669966996699,
+               0xA55A5AA5A55A5AA5,
+               0x3C3C3C3CC3C3C3C3,
+               0x3CC33CC3C33CC33C,
+               0xCCCC3333CCCC3333,
+               0x9999999966666666,
+               0x3CC33CC33CC33CC3,
+               0x6666999999996666,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0x55555555AAAAAAAA,
+               0xF00FF00F0FF00FF0,
+               0x5AA55AA5A55AA55A,
+               0x55AAAA55AA5555AA,
+               0xF00F0FF0F00F0FF0,
+               0x9669699696696996,
+               0xA55AA55AA55AA55A,
+               0x55555555AAAAAAAA,
+               0xCCCC33333333CCCC,
+               0x0000FFFFFFFF0000,
+               0xFF0000FF00FFFF00,
+               0x6996699669966996,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0x55555555AAAAAAAA,
+               0x0FF00FF0F00FF00F,
+               0x5AA55AA5A55AA55A,
+               0x55AAAA55AA5555AA,
+               0xF00F0FF0F00F0FF0,
+               0x9669699696696996,
+               0x5AA55AA55AA55AA5,
+               0x55555555AAAAAAAA,
+               0x3333CCCCCCCC3333,
+               0x0000FFFFFFFF0000,
+               0x00FFFF00FF0000FF,
+               0x9669966996699669,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0x55555555AAAAAAAA,
+               0xF00FF00F0FF00FF0,
+               0xA55AA55A5AA55AA5,
+               0xAA5555AA55AAAA55,
+               0x0FF0F00F0FF0F00F,
+               0x9669699696696996,
+               0x5AA55AA55AA55AA5,
+               0xAAAAAAAA55555555,
+               0x3333CCCCCCCC3333,
+               0xFFFF00000000FFFF,
+               0xFF0000FF00FFFF00,
+               0x9669966996699669,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0x55555555AAAAAAAA,
+               0x0FF00FF0F00FF00F,
+               0xA55AA55A5AA55AA5,
+               0xAA5555AA55AAAA55,
+               0x0FF0F00F0FF0F00F,
+               0x9669699696696996,
+               0xA55AA55AA55AA55A,
+               0xAAAAAAAA55555555,
+               0xCCCC33333333CCCC,
+               0xFFFF00000000FFFF,
+               0x00FFFF00FF0000FF,
+               0x6996699669966996,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0x55555555AAAAAAAA,
+               0x0FF00FF0F00FF00F,
+               0xA55AA55A5AA55AA5,
+               0xAA5555AA55AAAA55,
+               0x0FF0F00F0FF0F00F,
+               0x6996966969969669,
+               0xA55AA55AA55AA55A,
+               0xAAAAAAAA55555555,
+               0xCCCC33333333CCCC,
+               0x0000FFFFFFFF0000,
+               0xFF0000FF00FFFF00,
+               0x6996699669966996,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0x55555555AAAAAAAA,
+               0xF00FF00F0FF00FF0,
+               0xA55AA55A5AA55AA5,
+               0xAA5555AA55AAAA55,
+               0x0FF0F00F0FF0F00F,
+               0x6996966969969669,
+               0x5AA55AA55AA55AA5,
+               0xAAAAAAAA55555555,
+               0x3333CCCCCCCC3333,
+               0x0000FFFFFFFF0000,
+               0x00FFFF00FF0000FF,
+               0x9669966996699669,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0x55555555AAAAAAAA,
+               0x0FF00FF0F00FF00F,
+               0x5AA55AA5A55AA55A,
+               0x55AAAA55AA5555AA,
+               0xF00F0FF0F00F0FF0,
+               0x6996966969969669,
+               0x5AA55AA55AA55AA5,
+               0x55555555AAAAAAAA,
+               0x3333CCCCCCCC3333,
+               0xFFFF00000000FFFF,
+               0xFF0000FF00FFFF00,
+               0x9669966996699669,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0x55555555AAAAAAAA,
+               0xF00FF00F0FF00FF0,
+               0x5AA55AA5A55AA55A,
+               0x55AAAA55AA5555AA,
+               0xF00F0FF0F00F0FF0,
+               0x6996966969969669,
+               0xA55AA55AA55AA55A,
+               0x55555555AAAAAAAA,
+               0xCCCC33333333CCCC,
+               0xFFFF00000000FFFF,
+               0x00FFFF00FF0000FF,
+               0x6996699669966996,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0xAAAAAAAA55555555,
+               0x0FF00FF0F00FF00F,
+               0x5AA55AA5A55AA55A,
+               0xAA5555AA55AAAA55,
+               0xF00F0FF0F00F0FF0,
+               0x9669699696696996,
+               0xA55AA55AA55AA55A,
+               0x55555555AAAAAAAA,
+               0xCCCC33333333CCCC,
+               0x0000FFFFFFFF0000,
+               0xFF0000FF00FFFF00,
+               0x6996699669966996,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0xAAAAAAAA55555555,
+               0xF00FF00F0FF00FF0,
+               0x5AA55AA5A55AA55A,
+               0xAA5555AA55AAAA55,
+               0xF00F0FF0F00F0FF0,
+               0x9669699696696996,
+               0x5AA55AA55AA55AA5,
+               0x55555555AAAAAAAA,
+               0x3333CCCCCCCC3333,
+               0x0000FFFFFFFF0000,
+               0x00FFFF00FF0000FF,
+               0x9669966996699669,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0xAAAAAAAA55555555,
+               0x0FF00FF0F00FF00F,
+               0xA55AA55A5AA55AA5,
+               0x55AAAA55AA5555AA,
+               0x0FF0F00F0FF0F00F,
+               0x9669699696696996,
+               0x5AA55AA55AA55AA5,
+               0xAAAAAAAA55555555,
+               0x3333CCCCCCCC3333,
+               0xFFFF00000000FFFF,
+               0xFF0000FF00FFFF00,
+               0x9669966996699669,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0xAAAAAAAA55555555,
+               0xF00FF00F0FF00FF0,
+               0xA55AA55A5AA55AA5,
+               0x55AAAA55AA5555AA,
+               0x0FF0F00F0FF0F00F,
+               0x9669699696696996,
+               0xA55AA55AA55AA55A,
+               0xAAAAAAAA55555555,
+               0xCCCC33333333CCCC,
+               0xFFFF00000000FFFF,
+               0x00FFFF00FF0000FF,
+               0x6996699669966996,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0xAAAAAAAA55555555,
+               0xF00FF00F0FF00FF0,
+               0xA55AA55A5AA55AA5,
+               0x55AAAA55AA5555AA,
+               0x0FF0F00F0FF0F00F,
+               0x6996966969969669,
+               0xA55AA55AA55AA55A,
+               0xAAAAAAAA55555555,
+               0xCCCC33333333CCCC,
+               0x0000FFFFFFFF0000,
+               0xFF0000FF00FFFF00,
+               0x6996699669966996,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0xAAAAAAAA55555555,
+               0x0FF00FF0F00FF00F,
+               0xA55AA55A5AA55AA5,
+               0x55AAAA55AA5555AA,
+               0x0FF0F00F0FF0F00F,
+               0x6996966969969669,
+               0x5AA55AA55AA55AA5,
+               0xAAAAAAAA55555555,
+               0x3333CCCCCCCC3333,
+               0x0000FFFFFFFF0000,
+               0x00FFFF00FF0000FF,
+               0x9669966996699669,
+       },
+       {
+               0x3C3CC3C3C3C33C3C,
+               0xAAAAAAAA55555555,
+               0xF00FF00F0FF00FF0,
+               0x5AA55AA5A55AA55A,
+               0xAA5555AA55AAAA55,
+               0xF00F0FF0F00F0FF0,
+               0x6996966969969669,
+               0x5AA55AA55AA55AA5,
+               0x55555555AAAAAAAA,
+               0x3333CCCCCCCC3333,
+               0xFFFF00000000FFFF,
+               0xFF0000FF00FFFF00,
+               0x9669966996699669,
+       },
+       {
+               0xC3C33C3C3C3CC3C3,
+               0xAAAAAAAA55555555,
+               0x0FF00FF0F00FF00F,
+               0x5AA55AA5A55AA55A,
+               0xAA5555AA55AAAA55,
+               0xF00F0FF0F00F0FF0,
+               0x6996966969969669,
+               0xA55AA55AA55AA55A,
+               0x55555555AAAAAAAA,
+               0xCCCC33333333CCCC,
+               0xFFFF00000000FFFF,
+               0x00FFFF00FF0000FF,
+               0x6996699669966996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0xAAAAAAAAAAAAAAAA,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0x0000FFFF0000FFFF,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0xC33C3CC3C33C3CC3,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0x55AA55AA55AA55AA,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0xFFFF0000FFFF0000,
+               0x0F0F0F0FF0F0F0F0,
+               0x00FFFF00FF0000FF,
+               0xCC3333CC33CCCC33,
+               0xFF0000FF00FFFF00,
+               0x6996966996696996,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x3CC3C33C3CC3C33C,
+               0x5555555555555555,
+               0xFFFF0000FFFF0000,
+               0x3CC3C33C3CC3C33C,
+               0xAA55AA55AA55AA55,
+               0x0000FFFF0000FFFF,
+               0xF0F0F0F00F0F0F0F,
+               0xFF0000FF00FFFF00,
+               0x33CCCC33CC3333CC,
+               0x00FFFF00FF0000FF,
+               0x9669699669969669,
+               0xA55A5AA55AA5A55A,
+               0x6996966996696996,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+}
+
+var RadixConversionsS = [5][2][gf2e13.Bits]uint64{
+       {
+               {
+                       0x3C3CF30C0000C003,
+                       0x0CCCC3F333C0000C,
+                       0x03C33F33FCC0C03C,
+                       0x0003000F3C03C0C0,
+                       0xF33FF33030CF03F0,
+                       0x0CF0303300F0CCC0,
+                       0xFF3F0C0CC0FF3CC0,
+                       0xCF3CF0FF003FC000,
+                       0xC00FF3CF0303F300,
+                       0x3CCC0CC00CF0CC00,
+                       0xF30FFC3C3FCCFC00,
+                       0x3F0FC3F0CCF0C000,
+                       0x3000FF33CCF0F000,
+               },
+               {
+                       0x0C0F0FCF0F0CF330,
+                       0xF0000FC33C3CCF3C,
+                       0x3C0F3F00C3C300FC,
+                       0x3C33CCC0F0F3CC30,
+                       0xC0CFFFFFCCCC30CC,
+                       0x3FC3F3CCFFFC033F,
+                       0xFC3030CCCCC0CFCF,
+                       0x0FCF0C00CCF333C3,
+                       0xCFFCF33000CFF030,
+                       0x00CFFCC330F30FCC,
+                       0x3CCC3FCCC0F3FFF3,
+                       0xF00F0C3FC003C0FF,
+                       0x330CCFCC03C0FC33,
+               },
+       },
+       {
+               {
+                       0x0F0F0FF0F000000F,
+                       0x00FFFFFFFF0000F0,
+                       0xFFFF00FF00000F00,
+                       0xFFF000F00F0FF000,
+                       0xFFF0000F0FF000F0,
+                       0x00FF000FFF000000,
+                       0xFF0F0FFF0F0FF000,
+                       0x0FFF0000000F0000,
+                       0x00F000F0FFF00F00,
+                       0x00F00FF00F00F000,
+                       0xFFF000F000F00000,
+                       0x00F00F000FF00000,
+                       0x0000FF0F0000F000,
+               },
+               {
+                       0xF0FFFFFFF0F00F00,
+                       0x00FFF0FFFF0000FF,
+                       0x00FF00000F0F0FFF,
+                       0xF000F0000F00FF0F,
+                       0xFF000000FFF00000,
+                       0xF0FF000FF00F0FF0,
+                       0x0F0F0F00FF000F0F,
+                       0x0F0F00F0F0F0F000,
+                       0x00F00F00F00F000F,
+                       0x00F0F0F00000FFF0,
+                       0xFFFFFF0FF00F0FFF,
+                       0x0F0FFFF00FFFFFFF,
+                       0xFFFF0F0FFF0FFF00,
+               },
+       },
+       {
+               {
+                       0x00FF0000000000FF,
+                       0xFFFFFFFFFF00FF00,
+                       0xFF0000FF00FF0000,
+                       0xFFFF000000FF0000,
+                       0xFF00000000FF0000,
+                       0x00FFFFFFFF000000,
+                       0xFF0000FFFFFF0000,
+                       0xFF00FF00FFFF0000,
+                       0x00FFFFFFFF00FF00,
+                       0xFFFF000000000000,
+                       0x00FF0000FF000000,
+                       0xFF00FF00FF000000,
+                       0x00FF00FFFF000000,
+               },
+               {
+                       0x00FF00FF00FF0000,
+                       0xFF00FFFF000000FF,
+                       0x0000FFFF000000FF,
+                       0x00FFFF00FF000000,
+                       0xFFFFFF0000FF00FF,
+                       0x0000FFFF00FFFF00,
+                       0xFF00FF0000FFFF00,
+                       0x00000000FFFFFFFF,
+                       0x0000FF0000000000,
+                       0xFF00FFFF00FFFF00,
+                       0x00FFFF00000000FF,
+                       0x0000FF00FF00FFFF,
+                       0xFF0000FFFFFF0000,
+               },
+       },
+       {
+               {
+                       0x000000000000FFFF,
+                       0xFFFFFFFFFFFF0000,
+                       0x0000000000000000,
+                       0xFFFF0000FFFF0000,
+                       0xFFFFFFFFFFFF0000,
+                       0x0000FFFF00000000,
+                       0x0000FFFFFFFF0000,
+                       0xFFFF0000FFFF0000,
+                       0x0000FFFF00000000,
+                       0xFFFF000000000000,
+                       0xFFFF000000000000,
+                       0xFFFF000000000000,
+                       0xFFFFFFFF00000000,
+               },
+               {
+                       0x0000FFFF00000000,
+                       0xFFFFFFFF0000FFFF,
+                       0x00000000FFFFFFFF,
+                       0x0000000000000000,
+                       0x0000FFFF00000000,
+                       0xFFFF0000FFFF0000,
+                       0x0000FFFFFFFF0000,
+                       0x0000FFFF0000FFFF,
+                       0xFFFFFFFF0000FFFF,
+                       0x00000000FFFF0000,
+                       0xFFFF0000FFFFFFFF,
+                       0xFFFF0000FFFFFFFF,
+                       0x0000000000000000,
+               },
+       },
+       {
+               {
+                       0x00000000FFFFFFFF,
+                       0x0000000000000000,
+                       0xFFFFFFFF00000000,
+                       0x0000000000000000,
+                       0xFFFFFFFF00000000,
+                       0xFFFFFFFF00000000,
+                       0xFFFFFFFF00000000,
+                       0x0000000000000000,
+                       0xFFFFFFFF00000000,
+                       0x0000000000000000,
+                       0x0000000000000000,
+                       0x0000000000000000,
+                       0xFFFFFFFF00000000,
+               },
+               {
+                       0x0000000000000000,
+                       0xFFFFFFFFFFFFFFFF,
+                       0x0000000000000000,
+                       0x0000000000000000,
+                       0x00000000FFFFFFFF,
+                       0xFFFFFFFF00000000,
+                       0x0000000000000000,
+                       0xFFFFFFFFFFFFFFFF,
+                       0x00000000FFFFFFFF,
+                       0xFFFFFFFF00000000,
+                       0xFFFFFFFFFFFFFFFF,
+                       0xFFFFFFFFFFFFFFFF,
+                       0xFFFFFFFF00000000,
+               },
+       },
+}
+
+var RadixConversionsS4096 = [5][gf2e12.Bits]uint64{
+       {
+               0xF3CFC030FC30F003,
+               0x3FCF0F003C00C00C,
+               0x30033CC300C0C03C,
+               0xCCFF0F3C0F30F0C0,
+               0x0300C03FF303C3F0,
+               0x3FFF3C0FF0CCCCC0,
+               0xF3FFF0C00F3C3CC0,
+               0x3003333FFFC3C000,
+               0x0FF30FFFC3FFF300,
+               0xFFC0F300F0F0CC00,
+               0xC0CFF3FCCC3CFC00,
+               0xFC3C03F0F330C000,
+       },
+       {
+               0x000F00000000F00F,
+               0x00000F00F00000F0,
+               0x0F00000F00000F00,
+               0xF00F00F00F000000,
+               0x00F00000000000F0,
+               0x0000000F00000000,
+               0xF00000000F00F000,
+               0x00F00F00000F0000,
+               0x0000F00000F00F00,
+               0x000F00F00F00F000,
+               0x00F00F0000000000,
+               0x0000000000F00000,
+       },
+       {
+               0x0000FF00FF0000FF,
+               0x0000FF000000FF00,
+               0xFF0000FF00FF0000,
+               0xFFFF0000FF000000,
+               0x00FF00FF00FF0000,
+               0x0000FFFFFF000000,
+               0x00FFFF00FF000000,
+               0xFFFFFF0000FF0000,
+               0xFFFF00FFFF00FF00,
+               0x0000FF0000000000,
+               0xFFFFFF00FF000000,
+               0x00FF000000000000,
+       },
+       {
+               0x000000000000FFFF,
+               0x00000000FFFF0000,
+               0x0000000000000000,
+               0xFFFF000000000000,
+               0x00000000FFFF0000,
+               0x0000FFFF00000000,
+               0x0000000000000000,
+               0x00000000FFFF0000,
+               0x0000FFFF00000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+       },
+       {
+               0x00000000FFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFFFFFF00000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+       },
+}
+
+var ButterfliesConsts4096 = [63][gf2e12.Bits]uint64{
+       // 64
+       {
+               0xF00F0FF0F00F0FF0,
+               0xF0F00F0F0F0FF0F0,
+               0x0FF00FF00FF00FF0,
+               0xAA5555AAAA5555AA,
+               0xF00F0FF0F00F0FF0,
+               0x33CCCC33CC3333CC,
+               0xFFFF0000FFFF0000,
+               0xCC33CC3333CC33CC,
+               0x33CC33CC33CC33CC,
+               0x5A5A5A5A5A5A5A5A,
+               0xFF00FF00FF00FF00,
+               0xF00F0FF0F00F0FF0,
+       },
+       // 128
+       {
+               0x3C3C3C3C3C3C3C3C,
+               0xF0F0F0F0F0F0F0F0,
+               0x5555AAAA5555AAAA,
+               0xCC3333CCCC3333CC,
+               0xC33CC33CC33CC33C,
+               0x55555555AAAAAAAA,
+               0x33333333CCCCCCCC,
+               0x00FF00FFFF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x0000FFFFFFFF0000,
+               0xF0F00F0F0F0FF0F0,
+       },
+       {
+               0x3C3C3C3C3C3C3C3C,
+               0x0F0F0F0F0F0F0F0F,
+               0xAAAA5555AAAA5555,
+               0xCC3333CCCC3333CC,
+               0xC33CC33CC33CC33C,
+               0x55555555AAAAAAAA,
+               0x33333333CCCCCCCC,
+               0xFF00FF0000FF00FF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x0000FFFFFFFF0000,
+               0xF0F00F0F0F0FF0F0,
+       },
+       // 256
+       {
+               0xAA55AA5555AA55AA,
+               0xCC33CC3333CC33CC,
+               0x33CCCC33CC3333CC,
+               0x55555555AAAAAAAA,
+               0xFF0000FF00FFFF00,
+               0x3CC33CC3C33CC33C,
+               0x5555AAAA5555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xCCCC33333333CCCC,
+               0xF0F0F0F0F0F0F0F0,
+               0x00FFFF0000FFFF00,
+               0xC33CC33CC33CC33C,
+       },
+       {
+               0x55AA55AAAA55AA55,
+               0xCC33CC3333CC33CC,
+               0xCC3333CC33CCCC33,
+               0x55555555AAAAAAAA,
+               0xFF0000FF00FFFF00,
+               0xC33CC33C3CC33CC3,
+               0xAAAA5555AAAA5555,
+               0xF00FF00FF00FF00F,
+               0x3333CCCCCCCC3333,
+               0x0F0F0F0F0F0F0F0F,
+               0xFF0000FFFF0000FF,
+               0xC33CC33CC33CC33C,
+       },
+       {
+               0xAA55AA5555AA55AA,
+               0x33CC33CCCC33CC33,
+               0xCC3333CC33CCCC33,
+               0x55555555AAAAAAAA,
+               0x00FFFF00FF0000FF,
+               0x3CC33CC3C33CC33C,
+               0x5555AAAA5555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x3333CCCCCCCC3333,
+               0xF0F0F0F0F0F0F0F0,
+               0x00FFFF0000FFFF00,
+               0xC33CC33CC33CC33C,
+       },
+       {
+               0x55AA55AAAA55AA55,
+               0x33CC33CCCC33CC33,
+               0x33CCCC33CC3333CC,
+               0x55555555AAAAAAAA,
+               0x00FFFF00FF0000FF,
+               0xC33CC33C3CC33CC3,
+               0xAAAA5555AAAA5555,
+               0xF00FF00FF00FF00F,
+               0xCCCC33333333CCCC,
+               0x0F0F0F0F0F0F0F0F,
+               0xFF0000FFFF0000FF,
+               0xC33CC33CC33CC33C,
+       },
+       // 512
+       {
+               0x6699669999669966,
+               0x33CCCC33CC3333CC,
+               0xA5A5A5A55A5A5A5A,
+               0x3C3CC3C3C3C33C3C,
+               0xF00FF00F0FF00FF0,
+               0x55AA55AA55AA55AA,
+               0x3C3CC3C3C3C33C3C,
+               0x0F0F0F0FF0F0F0F0,
+               0x55AA55AA55AA55AA,
+               0x33CCCC33CC3333CC,
+               0xF0F0F0F0F0F0F0F0,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x9966996666996699,
+               0x33CCCC33CC3333CC,
+               0xA5A5A5A55A5A5A5A,
+               0x3C3CC3C3C3C33C3C,
+               0x0FF00FF0F00FF00F,
+               0xAA55AA55AA55AA55,
+               0x3C3CC3C3C3C33C3C,
+               0xF0F0F0F00F0F0F0F,
+               0xAA55AA55AA55AA55,
+               0xCC3333CC33CCCC33,
+               0x0F0F0F0F0F0F0F0F,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x6699669999669966,
+               0x33CCCC33CC3333CC,
+               0x5A5A5A5AA5A5A5A5,
+               0xC3C33C3C3C3CC3C3,
+               0x0FF00FF0F00FF00F,
+               0xAA55AA55AA55AA55,
+               0xC3C33C3C3C3CC3C3,
+               0x0F0F0F0FF0F0F0F0,
+               0xAA55AA55AA55AA55,
+               0x33CCCC33CC3333CC,
+               0xF0F0F0F0F0F0F0F0,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x9966996666996699,
+               0x33CCCC33CC3333CC,
+               0x5A5A5A5AA5A5A5A5,
+               0xC3C33C3C3C3CC3C3,
+               0xF00FF00F0FF00FF0,
+               0x55AA55AA55AA55AA,
+               0xC3C33C3C3C3CC3C3,
+               0xF0F0F0F00F0F0F0F,
+               0x55AA55AA55AA55AA,
+               0xCC3333CC33CCCC33,
+               0x0F0F0F0F0F0F0F0F,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x6699669999669966,
+               0xCC3333CC33CCCC33,
+               0x5A5A5A5AA5A5A5A5,
+               0x3C3CC3C3C3C33C3C,
+               0x0FF00FF0F00FF00F,
+               0x55AA55AA55AA55AA,
+               0x3C3CC3C3C3C33C3C,
+               0x0F0F0F0FF0F0F0F0,
+               0x55AA55AA55AA55AA,
+               0x33CCCC33CC3333CC,
+               0xF0F0F0F0F0F0F0F0,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x9966996666996699,
+               0xCC3333CC33CCCC33,
+               0x5A5A5A5AA5A5A5A5,
+               0x3C3CC3C3C3C33C3C,
+               0xF00FF00F0FF00FF0,
+               0xAA55AA55AA55AA55,
+               0x3C3CC3C3C3C33C3C,
+               0xF0F0F0F00F0F0F0F,
+               0xAA55AA55AA55AA55,
+               0xCC3333CC33CCCC33,
+               0x0F0F0F0F0F0F0F0F,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x6699669999669966,
+               0xCC3333CC33CCCC33,
+               0xA5A5A5A55A5A5A5A,
+               0xC3C33C3C3C3CC3C3,
+               0xF00FF00F0FF00FF0,
+               0xAA55AA55AA55AA55,
+               0xC3C33C3C3C3CC3C3,
+               0x0F0F0F0FF0F0F0F0,
+               0xAA55AA55AA55AA55,
+               0x33CCCC33CC3333CC,
+               0xF0F0F0F0F0F0F0F0,
+               0xA55A5AA55AA5A55A,
+       },
+       {
+               0x9966996666996699,
+               0xCC3333CC33CCCC33,
+               0xA5A5A5A55A5A5A5A,
+               0xC3C33C3C3C3CC3C3,
+               0x0FF00FF0F00FF00F,
+               0x55AA55AA55AA55AA,
+               0xC3C33C3C3C3CC3C3,
+               0xF0F0F0F00F0F0F0F,
+               0x55AA55AA55AA55AA,
+               0xCC3333CC33CCCC33,
+               0x0F0F0F0F0F0F0F0F,
+               0xA55A5AA55AA5A55A,
+       },
+       // 1024
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x6996699669966996,
+               0x00FFFF0000FFFF00,
+               0xFF00FF00FF00FF00,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x6996699669966996,
+               0x00FFFF0000FFFF00,
+               0x00FF00FF00FF00FF,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x6996699669966996,
+               0xFF0000FFFF0000FF,
+               0x00FF00FF00FF00FF,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x6996699669966996,
+               0xFF0000FFFF0000FF,
+               0xFF00FF00FF00FF00,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x9669966996699669,
+               0xFF0000FFFF0000FF,
+               0x00FF00FF00FF00FF,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x9669966996699669,
+               0xFF0000FFFF0000FF,
+               0xFF00FF00FF00FF00,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x9669966996699669,
+               0x00FFFF0000FFFF00,
+               0xFF00FF00FF00FF00,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x6996699669966996,
+               0x9669966996699669,
+               0x00FFFF0000FFFF00,
+               0x00FF00FF00FF00FF,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x9669966996699669,
+               0x00FFFF0000FFFF00,
+               0xFF00FF00FF00FF00,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x9669966996699669,
+               0x00FFFF0000FFFF00,
+               0x00FF00FF00FF00FF,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x9669966996699669,
+               0xFF0000FFFF0000FF,
+               0x00FF00FF00FF00FF,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x9669966996699669,
+               0xFF0000FFFF0000FF,
+               0xFF00FF00FF00FF00,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x6996699669966996,
+               0xFF0000FFFF0000FF,
+               0x00FF00FF00FF00FF,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x6996699669966996,
+               0xFF0000FFFF0000FF,
+               0xFF00FF00FF00FF00,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x6996699669966996,
+               0x00FFFF0000FFFF00,
+               0xFF00FF00FF00FF00,
+               0x0FF00FF0F00FF00F,
+               0x0F0FF0F0F0F00F0F,
+               0xC33C3CC33CC3C33C,
+               0xC33C3CC33CC3C33C,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       {
+               0x9669699696696996,
+               0x9669966996699669,
+               0x6996699669966996,
+               0x00FFFF0000FFFF00,
+               0x00FF00FF00FF00FF,
+               0xF00FF00F0FF00FF0,
+               0xF0F00F0F0F0FF0F0,
+               0x3CC3C33CC33C3CC3,
+               0x3CC3C33CC33C3CC3,
+               0xA55A5AA55AA5A55A,
+               0xC33C3CC33CC3C33C,
+               0x3CC3C33C3CC3C33C,
+       },
+       // 2048
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0000000000000000,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0000000000000000,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xFFFFFFFF00000000,
+               0xFFFF0000FFFF0000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCCCCCCCCCCCCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/powers.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/internal/powers.go
new file mode 100644 (file)
index 0000000..c48d860
--- /dev/null
@@ -0,0 +1,2828 @@
+package internal
+
+import (
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e12"
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e13"
+)
+
+var Powers4096 = [64][gf2e12.Bits]uint64{
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0x3333CCCC3333CCCC,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0x0000000000000000,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0xFF00FF00FF00FF00,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0xAAAAAAAAAAAAAAAA,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0xF0F0F0F00F0F0F0F,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0xF0F0F0F0F0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFF0000FFFF0000,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0x0000000000000000,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0xFFFFFFFFFFFFFFFF,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0xAA55AA55AA55AA55,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+       {
+               0x0F0F0F0FF0F0F0F0,
+               0x0000FFFF0000FFFF,
+               0xFFFFFFFFFFFFFFFF,
+               0x0F0F0F0F0F0F0F0F,
+               0xFFFFFFFFFFFFFFFF,
+               0x55AA55AA55AA55AA,
+               0x0F0F0F0FF0F0F0F0,
+               0x0000000000000000,
+               0x00FF00FF00FF00FF,
+               0xF0F0F0F0F0F0F0F0,
+               0xCCCC3333CCCC3333,
+               0x5555555555555555,
+       },
+}
+
+var Powers8192 = [128][gf2e13.Bits]uint64{
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0x00000000FFFFFFFF,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0x5A5A5A5A5A5A5A5A,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0xCC33CC33CC33CC33,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0xCC33CC33CC33CC33,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x9696969669696969,
+               0xA5A5A5A5A5A5A5A5,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0x0F0FF0F00F0FF0F0,
+       },
+       {
+               0xA55AA55A5AA55AA5,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0x5A5A5A5A5A5A5A5A,
+               0xA5A5A5A55A5A5A5A,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0x3CC33CC3C33CC33C,
+               0xA5A55A5AA5A55A5A,
+               0x0000FFFF0000FFFF,
+               0x33CC33CC33CC33CC,
+               0xF00FF00F0FF00FF0,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0x5555AAAAAAAA5555,
+               0xF00FF00FF00FF00F,
+               0xF0F00F0FF0F00F0F,
+       },
+       {
+               0x5AA55AA5A55AA55A,
+               0xC33CC33C3CC33CC3,
+               0xA5A55A5AA5A55A5A,
+               0xFFFF0000FFFF0000,
+               0x33CC33CC33CC33CC,
+               0x0FF00FF0F00FF00F,
+               0xFFFFFFFF00000000,
+               0x6969696996969696,
+               0xA5A5A5A5A5A5A5A5,
+               0x5A5A5A5AA5A5A5A5,
+               0xAAAA55555555AAAA,
+               0x0FF00FF00FF00FF0,
+               0x0F0FF0F00F0FF0F0,
+       },
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e12/gf4096.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e12/gf4096.go
new file mode 100644 (file)
index 0000000..e0f84fa
--- /dev/null
@@ -0,0 +1,83 @@
+// Package gf2e12 provides finite field arithmetic over GF(2^12).
+package gf2e12
+
+// Elt is a field element of characteristic 2 modulo z^12 + z^3 + 1
+type Elt = uint16
+
+const (
+       Bits = 12
+       Mask = (1 << Bits) - 1
+)
+
+// Add two Elt elements together. Since an addition in Elt(2) is the same as XOR,
+// this implementation uses a simple XOR for addition.
+func Add(a, b Elt) Elt {
+       return a ^ b
+}
+
+// Mul calculate the product of two Elt elements.
+func Mul(a, b Elt) Elt {
+       a64 := uint64(a)
+       b64 := uint64(b)
+
+       // if the LSB of b is 1, set tmp to a64, and 0 otherwise
+       tmp := a64 & -(b64 & 1)
+
+       // check if i-th bit of b64 is set, add a64 shifted by i bits if so
+       for i := 1; i < Bits; i++ {
+               tmp ^= a64 * (b64 & (1 << i))
+       }
+
+       // polynomial reduction
+       t := tmp & 0x7FC000
+       tmp ^= t >> 9
+       tmp ^= t >> 12
+
+       t = tmp & 0x3000
+       tmp ^= t >> 9
+       tmp ^= t >> 12
+
+       return Elt(tmp & Mask)
+}
+
+// sqr calculates the square of Elt element a
+func sqr(a Elt) Elt {
+       a32 := uint32(a)
+       a32 = (a32 | (a32 << 8)) & 0x00FF00FF
+       a32 = (a32 | (a32 << 4)) & 0x0F0F0F0F
+       a32 = (a32 | (a32 << 2)) & 0x33333333
+       a32 = (a32 | (a32 << 1)) & 0x55555555
+
+       t := a32 & 0x7FC000
+       a32 ^= t >> 9
+       a32 ^= t >> 12
+
+       t = a32 & 0x3000
+       a32 ^= t >> 9
+       a32 ^= t >> 12
+
+       return uint16(a32 & Mask)
+}
+
+// Inv calculates the multiplicative inverse of Elt element a
+func Inv(a Elt) Elt {
+       out := sqr(a)
+       tmp3 := Mul(out, a) // a^3
+
+       out = sqr(sqr(tmp3))
+       tmp15 := Mul(out, tmp3) // a^15 = a^(3*2*2 + 3)
+
+       out = sqr(sqr(sqr(sqr(tmp15))))
+       out = Mul(out, tmp15) // a^255 = a^(15*2*2*2*2 + 15)
+
+       out = sqr(sqr(out))
+       out = Mul(out, tmp3) // a^1023 = a^(255*2*2 + 3)
+
+       out = Mul(sqr(out), a) // a^2047 = a^(1023*2 + 1)
+       return sqr(out)        // a^4094 = a^(2047 * 2)
+}
+
+// Div calculates a / b
+func Div(a, b Elt) Elt {
+       return Mul(Inv(b), a)
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e13/gf8192.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e13/gf8192.go
new file mode 100644 (file)
index 0000000..c2efcf2
--- /dev/null
@@ -0,0 +1,130 @@
+// Package gf2e13 provides finite field arithmetic over GF(2^13).
+package gf2e13
+
+// Elt is a field element of characteristic 2 modulo z^13 + z^4 + z^3 + z + 1
+type Elt = uint16
+
+const (
+       Bits = 13
+       Mask = (1 << Bits) - 1
+)
+
+// Add two Elt elements together. Since an addition in Elt(2) is the same as XOR,
+// this implementation uses a simple XOR for addition.
+func Add(a, b Elt) Elt {
+       return a ^ b
+}
+
+// Mul calculate the product of two Elt elements.
+func Mul(a, b Elt) Elt {
+       a64 := uint64(a)
+       b64 := uint64(b)
+
+       // if the LSB of b is 1, set tmp to a64, and 0 otherwise
+       tmp := a64 & -(b64 & 1)
+
+       // check if i-th bit of b64 is set, add a64 shifted by i bits if so
+       for i := 1; i < Bits; i++ {
+               tmp ^= a64 * (b64 & (1 << i))
+       }
+
+       // polynomial reduction
+       t := tmp & 0x1FF0000
+       tmp ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+
+       t = tmp & 0x000E000
+       tmp ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+
+       return uint16(tmp & Mask)
+}
+
+// sqr2 calculates a^4
+func sqr2(a Elt) Elt {
+       a64 := uint64(a)
+       a64 = (a64 | (a64 << 24)) & 0x000000FF000000FF
+       a64 = (a64 | (a64 << 12)) & 0x000F000F000F000F
+       a64 = (a64 | (a64 << 6)) & 0x0303030303030303
+       a64 = (a64 | (a64 << 3)) & 0x1111111111111111
+
+       t := a64 & 0x0001FF0000000000
+       a64 ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = a64 & 0x000000FF80000000
+       a64 ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = a64 & 0x000000007FC00000
+       a64 ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = a64 & 0x00000000003FE000
+       a64 ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+
+       return uint16(a64 & Mask)
+}
+
+// sqrMul calculates the product of a^2 and b
+func sqrMul(a, b Elt) Elt {
+       a64 := uint64(a)
+       b64 := uint64(b)
+
+       x := (b64 << 6) * (a64 & (1 << 6))
+       a64 ^= a64 << 7
+       x ^= b64 * (a64 & (0x04001))
+       x ^= (b64 * (a64 & (0x08002))) << 1
+       x ^= (b64 * (a64 & (0x10004))) << 2
+       x ^= (b64 * (a64 & (0x20008))) << 3
+       x ^= (b64 * (a64 & (0x40010))) << 4
+       x ^= (b64 * (a64 & (0x80020))) << 5
+
+       t := x & 0x0000001FF0000000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x000000000FF80000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x000000000007E000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+
+       return uint16(x & Mask)
+}
+
+// sqr2Mul calculates the product of a^4 and b
+func sqr2Mul(a, b Elt) Elt {
+       a64 := uint64(a)
+       b64 := uint64(b)
+
+       x := (b64 << 18) * (a64 & (1 << 6))
+       a64 ^= a64 << 21
+       x ^= b64 * (a64 & (0x010000001))
+       x ^= (b64 * (a64 & (0x020000002))) << 3
+       x ^= (b64 * (a64 & (0x040000004))) << 6
+       x ^= (b64 * (a64 & (0x080000008))) << 9
+       x ^= (b64 * (a64 & (0x100000010))) << 12
+       x ^= (b64 * (a64 & (0x200000020))) << 15
+
+       t := x & 0x1FF0000000000000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x000FF80000000000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x000007FC00000000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x00000003FE000000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x0000000001FE0000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+       t = x & 0x000000000001E000
+       x ^= (t >> 9) ^ (t >> 10) ^ (t >> 12) ^ (t >> 13)
+
+       return uint16(x & Mask)
+}
+
+// Inv calculates the multiplicative inverse of Elt element a
+func Inv(a Elt) Elt {
+       return Div(1, a)
+}
+
+// Div calculates a / b
+func Div(a, b Elt) Elt {
+       tmp3 := sqrMul(b, b)         // b^3
+       tmp15 := sqr2Mul(tmp3, tmp3) // b^15 = b^(3*2*2+3)
+       out := sqr2(tmp15)
+       out = sqr2Mul(out, tmp15) // b^255 = b^(15*4*4+15)
+       out = sqr2(out)
+       out = sqr2Mul(out, tmp15) // b^4095 = b^(255*2*2*2*2+15)
+
+       return sqrMul(out, a) // b^8190 = b^(4095*2) = b^-1
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/mceliece.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/mceliece.go
new file mode 100644 (file)
index 0000000..7b11661
--- /dev/null
@@ -0,0 +1,733 @@
+// Code generated from mceliece.templ.go. DO NOT EDIT.
+
+// Package mceliece6960119 implements the IND-CCA2 secure key encapsulation mechanism
+// mceliece6960119 as submitted to round 4 of the NIST PQC competition and
+// described in
+//
+// https://classic.mceliece.org/nist/mceliece-20201010.pdf
+//
+// The following code is translated from the C reference implementation, and
+// from a Rust implementation by Bernhard Berg, Lukas Prokop, Daniel Kales
+// where direct translation from C is not applicable.
+//
+// https://github.com/Colfenor/classic-mceliece-rust
+package mceliece6960119
+
+import (
+       cryptoRand "crypto/rand"
+       "crypto/sha3"
+       "errors"
+       "fmt"
+       "io"
+
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/internal"
+       "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/math/gf2e13"
+)
+
+const (
+       sysT                  = 119 // F(y) is 64 degree
+       gfBits                = gf2e13.Bits
+       gfMask                = gf2e13.Mask
+       unusedBits            = 16 - gfBits
+       sysN                  = 6960
+       condBytes             = (1 << (gfBits - 4)) * (2*gfBits - 1)
+       irrBytes              = sysT * 2
+       pkNRows               = sysT * gfBits
+       pkNCols               = sysN - pkNRows
+       pkRowBytes            = (pkNCols + 7) / 8
+       syndBytes             = (pkNRows + 7) / 8
+       PublicKeySize         = 1047319
+       PrivateKeySize        = 13948
+       CiphertextSize        = 194
+       SharedKeySize         = 32
+       seedSize              = 32
+       encapsulationSeedSize = 48
+)
+
+var (
+       ErrCiphertextSize = errors.New("wrong size for ciphertext")
+       ErrPubKeySize     = errors.New("wrong size for public key")
+       ErrPrivKeySize    = errors.New("wrong size for private key")
+)
+
+type PublicKey struct {
+       pk [PublicKeySize]byte
+}
+
+type PrivateKey struct {
+       sk [PrivateKeySize]byte
+}
+
+type (
+       gf       = gf2e13.Elt
+       randFunc = func(pool []byte) error
+)
+
+// KEM Keypair generation.
+//
+// The structure of the secret key is given by the following segments:
+// (32 bytes seed, 8 bytes pivots, IRR_BYTES bytes, COND_BYTES bytes, SYS_N/8 bytes).
+// The structure of the public key is simple: a matrix of PK_NROWS times PK_ROW_BYTES bytes.
+//
+// `entropy` corresponds to the l-bit input seed in SeededKeyGen from the specification.
+// The keypair is deterministically generated from `entropy`.
+// If the generated keypair is invalid, a new seed will be generated by hashing `entropy` to try again.
+func deriveKeyPair(entropy []byte) (*PublicKey, *PrivateKey) {
+       const (
+               irrPolys  = sysN/8 + (1<<gfBits)*4
+               seedIndex = sysN/8 + (1<<gfBits)*4 + sysT*2
+               permIndex = sysN / 8
+               sBase     = 32 + 8 + irrBytes + condBytes
+       )
+
+       var (
+               pk [PublicKeySize]byte
+               sk [PrivateKeySize]byte
+       )
+
+       seed := [33]byte{64}
+       r := [sysN/8 + (1<<gfBits)*4 + sysT*2 + 32]byte{}
+
+       f := [sysT]gf{}
+       irr := [sysT]gf{}
+       perm := [1 << gfBits]uint32{}
+       pi := [1 << gfBits]int16{}
+       pivots := uint64(0xFFFFFFFF)
+
+       copy(seed[1:], entropy[:])
+
+       for {
+               // expanding and updating the seed
+               err := shake256(r[:], seed[0:33])
+               if err != nil {
+                       panic(err)
+               }
+
+               copy(sk[:32], seed[1:])
+               copy(seed[1:], r[len(r)-32:])
+
+               temp := r[irrPolys:seedIndex]
+               for i := 0; i < sysT; i++ {
+                       f[i] = loadGf(temp)
+                       temp = temp[2:]
+               }
+
+               if !minimalPolynomial(&irr, &f) {
+                       continue
+               }
+
+               temp = sk[40 : 40+irrBytes]
+               for i := 0; i < sysT; i++ {
+                       storeGf(temp, irr[i])
+                       temp = temp[2:]
+               }
+
+               // generating permutation
+               temp = r[permIndex:irrPolys]
+               for i := 0; i < 1<<gfBits; i++ {
+                       perm[i] = load4(temp)
+                       temp = temp[4:]
+               }
+
+               if !pkGen(&pk, sk[40:40+irrBytes], &perm, &pi, &pivots) {
+                       continue
+               }
+
+               internal.ControlBitsFromPermutation(sk[32+8+irrBytes:], pi[:], gfBits, 1<<gfBits)
+               copy(sk[sBase:sBase+sysN/8], r[0:sysN/8])
+               store8(sk[32:40], pivots)
+               return &PublicKey{pk: pk}, &PrivateKey{sk: sk}
+       }
+}
+
+// Encryption routine.
+// Takes a public key `pk` to compute error vector `e` and syndrome `s`.
+func encrypt(s *[CiphertextSize]byte, pk *[PublicKeySize]byte, e *[sysN / 8]byte, rand randFunc) error {
+       err := genE(e, rand)
+       if err != nil {
+               return err
+       }
+       syndrome(s, pk, e)
+       return nil
+}
+
+// KEM Encapsulation.
+//
+// Given a public key `pk`, sample a shared key.
+// This shared key is returned through parameter `key` whereas
+// the ciphertext (meant to be used for decapsulation) is returned as `c`.
+func kemEncapsulate(c *[CiphertextSize]byte, key *[SharedKeySize]byte, pk *[PublicKeySize]byte, rand randFunc) error {
+       e := [sysN / 8]byte{}
+       oneEC := [1 + sysN/8 + syndBytes]byte{1}
+
+       paddingOk := checkPkPadding(pk)
+
+       err := encrypt(c, pk, &e, rand)
+       if err != nil {
+               return err
+       }
+       copy(oneEC[1:1+sysN/8], e[:sysN/8])
+       copy(oneEC[1+sysN/8:1+sysN/8+syndBytes], c[:syndBytes])
+       err = shake256(key[0:32], oneEC[:])
+       if err != nil {
+               return err
+       }
+
+       mask := paddingOk ^ 0xFF
+       for i := 0; i < syndBytes; i++ {
+               c[i] &= mask
+       }
+       for i := 0; i < 32; i++ {
+               key[i] &= mask
+       }
+
+       if paddingOk == 0 {
+               return nil
+       }
+       return fmt.Errorf("public key padding error %d", paddingOk)
+}
+
+// KEM Decapsulation.
+//
+// Given a secret key `sk` and a ciphertext `c`,
+// determine the shared text `key` negotiated by both parties.
+func kemDecapsulate(key *[SharedKeySize]byte, c *[CiphertextSize]byte, sk *[PrivateKeySize]byte) error {
+       e := [sysN / 8]byte{}
+       preimage := [1 + sysN/8 + syndBytes]byte{}
+       s := sk[40+irrBytes+condBytes:]
+
+       paddingOk := checkCPadding(c)
+
+       retDecrypt := decrypt((*[sysN / 8]byte)(e[:sysN/8]), sk[40:], (*[syndBytes]byte)(c[:syndBytes]))
+       m := retDecrypt
+       m -= 1
+       m >>= 8
+
+       preimage[0] = byte(m & 1)
+       for i := 0; i < sysN/8; i++ {
+               preimage[1+i] = (byte(^m) & s[i]) | (byte(m) & e[i])
+       }
+
+       copy(preimage[1+sysN/8:][:syndBytes], c[0:syndBytes])
+       err := shake256(key[0:32], preimage[:])
+       if err != nil {
+               return err
+       }
+
+       // clear outputs (set to all 1's) if padding bits are not all zero
+       mask := paddingOk
+       for i := 0; i < 32; i++ {
+               key[i] |= mask
+       }
+
+       if paddingOk == 0 {
+               return nil
+       }
+       return fmt.Errorf("public key padding error %d", paddingOk)
+}
+
+// Generates `e`, a random error vector of weight `t`.
+// If generation of pseudo-random numbers fails, an error is returned
+func genE(e *[sysN / 8]byte, rand randFunc) error {
+       ind := [sysT]uint16{}
+       val := [sysT]byte{}
+       for {
+               buf := make([]byte, sysT*4)
+               err := rand(buf)
+               if err != nil {
+                       return err
+               }
+
+               nums := [sysT * 2]uint16{}
+               for i := 0; i < sysT*2; i++ {
+                       nums[i] = loadGf(buf[:])
+                       buf = buf[2:]
+               }
+
+               count := 0
+               for i := 0; i < sysT*2 && count < sysT; i++ {
+                       if nums[i] < sysN {
+                               ind[count] = nums[i]
+                               count++
+                       }
+               }
+               if count < sysT {
+                       continue
+               }
+
+               eq := false
+               for i := 1; i < sysT; i++ {
+                       for j := 0; j < i; j++ {
+                               if ind[i] == ind[j] {
+                                       eq = true
+                               }
+                       }
+               }
+
+               if !eq {
+                       break
+               }
+       }
+
+       for j := 0; j < sysT; j++ {
+               val[j] = 1 << (ind[j] & 7)
+       }
+
+       for i := uint16(0); i < sysN/8; i++ {
+               e[i] = 0
+
+               for j := 0; j < sysT; j++ {
+                       mask := sameMask(i, ind[j]>>3)
+                       e[i] |= val[j] & mask
+               }
+       }
+       return nil
+}
+
+// Takes two 16-bit integers and determines whether they are equal
+// Return byte with all bit set if equal, 0 otherwise
+func sameMask(x uint16, y uint16) byte {
+       mask := uint32(x ^ y)
+       mask -= 1
+       mask >>= 31
+       mask = -mask
+
+       return byte(mask & 0xFF)
+}
+
+// Given condition bits `c`, returns the support `s`.
+func supportGen(s *[sysN]gf, c *[condBytes]byte) {
+       L := [gfBits][(1 << gfBits) / 8]byte{}
+       for i := 0; i < (1 << gfBits); i++ {
+               a := bitRev(gf(i))
+               for j := 0; j < gfBits; j++ {
+                       L[j][i/8] |= byte(((a >> j) & 1) << (i % 8))
+               }
+       }
+       for j := 0; j < gfBits; j++ {
+               applyBenes(&L[j], c)
+       }
+       for i := 0; i < sysN; i++ {
+               s[i] = 0
+               for j := gfBits - 1; j >= 0; j-- {
+                       s[i] <<= 1
+                       s[i] |= uint16(L[j][i/8]>>(i%8)) & 1
+               }
+       }
+}
+
+// Given Goppa polynomial `f`, support `l`, and received word `r`
+// compute `out`, the syndrome of length 2t
+func synd(out *[sysT * 2]gf, f *[sysT + 1]gf, L *[sysN]gf, r *[sysN / 8]byte) {
+       for j := 0; j < 2*sysT; j++ {
+               out[j] = 0
+       }
+
+       for i := 0; i < sysN; i++ {
+               c := uint16(r[i/8]>>(i%8)) & 1
+               e := eval(f, L[i])
+               eInv := gf2e13.Inv(gf2e13.Mul(e, e))
+               for j := 0; j < 2*sysT; j++ {
+                       out[j] = gf2e13.Add(out[j], gf2e13.Mul(eInv, c))
+                       eInv = gf2e13.Mul(eInv, L[i])
+               }
+       }
+}
+
+func min(a, b int) int {
+       if a > b {
+               return b
+       }
+       return a
+}
+
+// The Berlekamp-Massey algorithm. <http://crypto.stanford.edu/~mironov/cs359/massey.pdf>
+// Uses `s` as input (sequence of field elements)
+// and `out` as output (minimal polynomial of `s`)
+func bm(out *[sysT + 1]gf, s *[2 * sysT]gf) {
+       var L, mle, mne uint16
+       T := [sysT + 1]gf{}
+       C := [sysT + 1]gf{}
+       B := [sysT + 1]gf{}
+       var b, d, f gf
+       b = 1
+       B[1] = 1
+       C[0] = 1
+       for N := 0; N < 2*sysT; N++ {
+               d = 0
+               for i := 0; i <= min(N, sysT); i++ {
+                       d ^= gf2e13.Mul(C[i], s[N-i])
+               }
+               mne = d
+               mne -= 1
+               mne >>= 15
+               mne -= 1
+               mle = uint16(N)
+               mle -= 2 * L
+               mle >>= 15
+               mle -= 1
+               mle &= mne
+               for i := 0; i <= sysT; i++ {
+                       T[i] = C[i]
+               }
+               f = gf2e13.Div(d, b)
+               for i := 0; i <= sysT; i++ {
+                       C[i] ^= gf2e13.Mul(f, B[i]) & mne
+               }
+               L = (L & ^mle) | ((uint16(N) + 1 - L) & mle)
+
+               for i := 0; i <= sysT; i++ {
+                       B[i] = (B[i] & ^mle) | (T[i] & mle)
+               }
+
+               b = (b & ^mle) | (d & mle)
+
+               for i := sysT; i >= 1; i-- {
+                       B[i] = B[i-1]
+               }
+               B[0] = 0
+       }
+
+       for i := 0; i <= sysT; i++ {
+               out[i] = C[sysT-i]
+       }
+}
+
+// Niederreiter decryption with the Berlekamp decoder.
+//
+// It takes as input the secret key `sk` and a ciphertext `c`.
+// It returns an error vector in `e` and the return value indicates success (0) or failure (1)
+func decrypt(e *[sysN / 8]byte, sk []byte, c *[syndBytes]byte) uint16 {
+       var check uint16
+       w := 0
+       r := [sysN / 8]byte{}
+
+       g := [sysT + 1]gf{}
+       L := [sysN]gf{}
+
+       s := [sysT * 2]gf{}
+       sCmp := [sysT * 2]gf{}
+       locator := [sysT + 1]gf{}
+       images := [sysN]gf{}
+
+       copy(r[:syndBytes], c[:syndBytes])
+       for i := 0; i < sysT; i++ {
+               g[i] = loadGf(sk)
+               sk = sk[2:]
+       }
+       g[sysT] = 1
+
+       supportGen(&L, (*[condBytes]byte)(sk[:condBytes]))
+
+       synd(&s, &g, &L, &r)
+       bm(&locator, &s)
+       root(&images, &locator, &L)
+
+       for i := 0; i < sysN/8; i++ {
+               e[i] = 0
+       }
+       for i := 0; i < sysN; i++ {
+               t := isZeroMask(images[i]) & 1
+
+               e[i/8] |= byte(t << (i % 8))
+               w += int(t)
+       }
+
+       synd(&sCmp, &g, &L, e)
+       check = uint16(w) ^ sysT
+       for i := 0; i < sysT*2; i++ {
+               check |= s[i] ^ sCmp[i]
+       }
+
+       check -= 1
+       check >>= 15
+
+       return check ^ 1
+}
+
+// check if element is 0, returns a mask with all bits set if so, and 0 otherwise
+func isZeroMask(element gf) uint16 {
+       t := uint32(element) - 1
+       t >>= 19
+       return uint16(t)
+}
+
+// calculate the minimal polynomial of f and store it in out
+func minimalPolynomial(out *[sysT]gf, f *[sysT]gf) bool {
+       mat := [sysT + 1][sysT]gf{}
+       mat[0][0] = 1
+       for i := 1; i < sysT; i++ {
+               mat[0][i] = 0
+       }
+
+       for i := 0; i < sysT; i++ {
+               mat[1][i] = f[i]
+       }
+
+       for i := 2; i <= sysT; i++ {
+               polyMul(&mat[i], &mat[i-1], f)
+       }
+
+       for j := 0; j < sysT; j++ {
+               for k := j + 1; k < sysT; k++ {
+                       mask := isZeroMask(mat[j][j])
+                       // if mat[j][j] is not zero, add mat[c..sysT+1][k] to mat[c][j]
+                       // do nothing otherwise
+                       for c := j; c <= sysT; c++ {
+                               mat[c][j] ^= mat[c][k] & mask
+                       }
+               }
+
+               if mat[j][j] == 0 {
+                       return false
+               }
+
+               inv := gf2e13.Inv(mat[j][j])
+               for c := 0; c <= sysT; c++ {
+                       mat[c][j] = gf2e13.Mul(mat[c][j], inv)
+               }
+
+               for k := 0; k < sysT; k++ {
+                       if k != j {
+                               t := mat[j][k]
+                               for c := 0; c <= sysT; c++ {
+                                       mat[c][k] ^= gf2e13.Mul(mat[c][j], t)
+                               }
+                       }
+               }
+       }
+
+       for i := 0; i < sysT; i++ {
+               out[i] = mat[sysT][i]
+       }
+
+       return true
+}
+
+// calculate the product of a and b in Fq^t
+func polyMul(out *[sysT]gf, a *[sysT]gf, b *[sysT]gf) {
+       product := [sysT*2 - 1]gf{}
+       for i := 0; i < sysT; i++ {
+               for j := 0; j < sysT; j++ {
+                       product[i+j] ^= gf2e13.Mul(a[i], b[j])
+               }
+       }
+
+       for i := (sysT - 1) * 2; i >= sysT; i-- {
+               // polynomial reduction
+
+               product[i-sysT+8] ^= product[i]
+               product[i-sysT+0] ^= product[i]
+
+       }
+
+       for i := 0; i < sysT; i++ {
+               out[i] = product[i]
+       }
+}
+
+// Compute transposition of `in` and store it in `out`
+func transpose64x64(out, in *[64]uint64) {
+       masks := [6][2]uint64{
+               {0x5555555555555555, 0xAAAAAAAAAAAAAAAA},
+               {0x3333333333333333, 0xCCCCCCCCCCCCCCCC},
+               {0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0},
+               {0x00FF00FF00FF00FF, 0xFF00FF00FF00FF00},
+               {0x0000FFFF0000FFFF, 0xFFFF0000FFFF0000},
+               {0x00000000FFFFFFFF, 0xFFFFFFFF00000000},
+       }
+       copy(out[:], in[:])
+
+       for d := 5; d >= 0; d-- {
+               s := 1 << d
+               for i := 0; i < 64; i += s * 2 {
+                       for j := i; j < i+s; j++ {
+                               x := (out[j] & masks[d][0]) | ((out[j+s] & masks[d][0]) << s)
+                               y := ((out[j] & masks[d][1]) >> s) | (out[j+s] & masks[d][1])
+
+                               out[j+0] = x
+                               out[j+s] = y
+                       }
+               }
+       }
+}
+
+// given polynomial `f`, evaluate `f` at `a`
+func eval(f *[sysT + 1]gf, a gf) gf {
+       r := f[sysT]
+       for i := sysT - 1; i >= 0; i-- {
+               r = gf2e13.Mul(r, a)
+               r = gf2e13.Add(r, f[i])
+       }
+       return r
+}
+
+// Given polynomial `f` and a list of field elements `l`,
+// return the roots `out` satisfying `[ f(a) for a in L ]`
+func root(out *[sysN]gf, f *[sysT + 1]gf, l *[sysN]gf) {
+       for i := 0; i < sysN; i++ {
+               out[i] = eval(f, l[i])
+       }
+}
+
+// performs SHAKE-256 on `input` and store the hash in `output`
+func shake256(output []byte, input []byte) error {
+       shake := sha3.NewSHAKE256()
+       _, err := shake.Write(input)
+       if err != nil {
+               return err
+       }
+       _, err = shake.Read(output)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// store field element `a` in the first 2 bytes of `dest`
+func storeGf(dest []byte, a gf) {
+       dest[0] = byte(a & 0xFF)
+       dest[1] = byte(a >> 8)
+}
+
+// load a field element from the first 2 bytes of `src`
+func loadGf(src []byte) gf {
+       a := uint16(src[1])
+       a <<= 8
+       a |= uint16(src[0])
+       return a & gfMask
+}
+
+// load a 32-bit little endian integer from `in`
+func load4(in []byte) uint32 {
+       ret := uint32(in[3])
+       for i := 2; i >= 0; i-- {
+               ret <<= 8
+               ret |= uint32(in[i])
+       }
+       return ret
+}
+
+// store a 64-bit integer to `out` in little endian
+func store8(out []byte, in uint64) {
+       out[0] = byte((in >> 0x00) & 0xFF)
+       out[1] = byte((in >> 0x08) & 0xFF)
+       out[2] = byte((in >> 0x10) & 0xFF)
+       out[3] = byte((in >> 0x18) & 0xFF)
+       out[4] = byte((in >> 0x20) & 0xFF)
+       out[5] = byte((in >> 0x28) & 0xFF)
+       out[6] = byte((in >> 0x30) & 0xFF)
+       out[7] = byte((in >> 0x38) & 0xFF)
+}
+
+// load a 64-bit little endian integer from `in`
+func load8(in []byte) uint64 {
+       ret := uint64(in[7])
+       for i := 6; i >= 0; i-- {
+               ret <<= 8
+               ret |= uint64(in[i])
+       }
+       return ret
+}
+
+// reverse the bits in the field element `a`
+func bitRev(a gf) gf {
+       a = ((a & 0x00FF) << 8) | ((a & 0xFF00) >> 8)
+       a = ((a & 0x0F0F) << 4) | ((a & 0xF0F0) >> 4)
+       a = ((a & 0x3333) << 2) | ((a & 0xCCCC) >> 2)
+       a = ((a & 0x5555) << 1) | ((a & 0xAAAA) >> 1)
+
+       return a >> unusedBits
+}
+
+func SeedSize() int              { return seedSize }
+func EncapsulationSeedSize() int { return encapsulationSeedSize }
+
+func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
+       var ret [PrivateKeySize]byte
+       copy(ret[:], sk.sk[:])
+       return ret[:], nil
+}
+
+// MarshalCompressedBinary returns a 32-byte seed that can be used to regenerate
+// the key pair when passed to DeriveKeyPair
+func (sk *PrivateKey) MarshalCompressedBinary() []byte {
+       seed := [32]byte{}
+       copy(seed[:], sk.sk[:32])
+       return seed[:]
+}
+
+func (sk *PrivateKey) Public() *PublicKey {
+       pk, _ := DeriveKeyPair(sk.MarshalCompressedBinary())
+       return pk
+}
+
+func (pk *PublicKey) MarshalBinary() ([]byte, error) {
+       var ret [PublicKeySize]byte
+       copy(ret[:], pk.pk[:])
+       return ret[:], nil
+}
+
+func GenerateKeyPair() (*PublicKey, *PrivateKey, error) {
+       seed := [32]byte{}
+       _, err := io.ReadFull(cryptoRand.Reader, seed[:])
+       if err != nil {
+               return nil, nil, err
+       }
+       pk, sk := deriveKeyPair(seed[:])
+       return pk, sk, nil
+}
+
+func DeriveKeyPair(seed []byte) (*PublicKey, *PrivateKey) {
+       if len(seed) != seedSize {
+               panic("seed must be of length EncapsulationSeedSize")
+       }
+       return deriveKeyPair(seed)
+}
+
+func encapsulate(pk *PublicKey, rand randFunc) (ct, ss []byte, err error) {
+       ciphertext := [CiphertextSize]byte{}
+       sharedSecret := [SharedKeySize]byte{}
+       err = kemEncapsulate(&ciphertext, &sharedSecret, &pk.pk, rand)
+       if err != nil {
+               return nil, nil, err
+       }
+       return ciphertext[:], sharedSecret[:], nil
+}
+
+func Encapsulate(pk *PublicKey) (ct, ss []byte, err error) {
+       return encapsulate(pk, func(pool []byte) error {
+               _, err2 := io.ReadFull(cryptoRand.Reader, pool)
+               return err2
+       })
+}
+
+func Decapsulate(sk *PrivateKey, ct []byte) ([]byte, error) {
+       if len(ct) != CiphertextSize {
+               return nil, ErrCiphertextSize
+       }
+       ss := [SharedKeySize]byte{}
+       err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &sk.sk)
+       if err != nil {
+               return nil, err
+       }
+       return ss[:], nil
+}
+
+func UnmarshalBinaryPublicKey(buf []byte) (*PublicKey, error) {
+       if len(buf) != PublicKeySize {
+               return nil, ErrPubKeySize
+       }
+       pk := [PublicKeySize]byte{}
+       copy(pk[:], buf)
+       return &PublicKey{pk: pk}, nil
+}
+
+func UnmarshalBinaryPrivateKey(buf []byte) (*PrivateKey, error) {
+       if len(buf) != PrivateKeySize {
+               return nil, ErrPrivKeySize
+       }
+       sk := [PrivateKeySize]byte{}
+       copy(sk[:], buf)
+       return &PrivateKey{sk: sk}, nil
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/operations.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/operations.go
new file mode 100644 (file)
index 0000000..d6a527b
--- /dev/null
@@ -0,0 +1,57 @@
+// Code generated from operations_6960119.templ.go. DO NOT EDIT.
+
+package mceliece6960119
+
+// This function determines (in a constant-time manner) whether the padding bits of `pk` are all zero.
+func checkPkPadding(pk *[PublicKeySize]byte) byte {
+       b := byte(0)
+       for i := 0; i < pkNRows; i++ {
+               b |= pk[i*pkRowBytes+pkRowBytes-1]
+       }
+       b >>= pkNCols % 8
+       b -= 1
+       b >>= 7
+       return b - 1
+}
+
+// This function determines (in a constant-time manner) whether the padding bits of `c` are all zero.
+func checkCPadding(c *[CiphertextSize]byte) byte {
+       b := c[syndBytes-1] >> (pkNRows % 8)
+       b -= 1
+       b >>= 7
+       return b - 1
+}
+
+// input: public key pk, error vector e
+// output: syndrome s
+func syndrome(s *[CiphertextSize]byte, pk *[PublicKeySize]byte, e *[sysN / 8]byte) {
+       row := [sysN / 8]byte{}
+       tail := pkNRows % 8
+       for i := 0; i < syndBytes; i++ {
+               s[i] = 0
+       }
+       for i := 0; i < pkNRows; i++ {
+               for j := 0; j < sysN/8; j++ {
+                       row[j] = 0
+               }
+               for j := 0; j < pkRowBytes; j++ {
+                       row[sysN/8-pkRowBytes+j] = pk[i*pkRowBytes+j]
+               }
+               for j := sysN/8 - 1; j >= sysN/8-pkRowBytes; j-- {
+                       row[j] = (row[j] << tail) | (row[j-1] >> (8 - tail))
+               }
+               row[i/8] |= 1 << (i % 8)
+
+               b := byte(0)
+               for j := 0; j < sysN/8; j++ {
+                       b ^= row[j] & e[j]
+               }
+
+               b ^= b >> 4
+               b ^= b >> 2
+               b ^= b >> 1
+               b &= 1
+
+               s[i/8] |= b << (i % 8)
+       }
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/pk_gen.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/pk_gen.go
new file mode 100644 (file)
index 0000000..742b6cc
--- /dev/null
@@ -0,0 +1,280 @@
+// Code generated from pk_gen_vec.templ.go. DO NOT EDIT.
+
+// The following code is translated from the C `vec` Additional Implementation
+// from the NIST round 4 submission package.
+
+package mceliece6960119
+
+import "go.cypherpunks.su/keks/cm/enc/mceliece6960119-x25519/mceliece6960119/internal"
+
+const exponent = 128
+
+func storeI(out []byte, in uint64, i int) {
+       for j := 0; j < i; j++ {
+               out[j] = byte((in >> (j * 8)) & 0xFF)
+       }
+}
+
+func deBitSlicing(out *[1 << gfBits]uint64, in *[exponent][gfBits]uint64) {
+       for i := 0; i < (1 << gfBits); i++ {
+               out[i] = 0
+       }
+
+       for i := 0; i < exponent; i++ {
+               for j := gfBits - 1; j >= 0; j-- {
+                       for r := 0; r < 64; r++ {
+                               out[i*64+r] <<= 1
+                               out[i*64+r] |= (in[i][j] >> r) & 1
+                       }
+               }
+       }
+}
+
+func toBitslicing2x(out0 *[exponent][gfBits]uint64, out1 *[exponent][gfBits]uint64, in *[1 << gfBits]uint64) {
+       for i := 0; i < exponent; i++ {
+               for j := gfBits - 1; j >= 0; j-- {
+                       for r := 63; r >= 0; r-- {
+                               out1[i][j] <<= 1
+                               out1[i][j] |= (in[i*64+r] >> (j + gfBits)) & 1
+                       }
+               }
+
+               for j := gfBits - 1; j >= 0; j-- {
+                       for r := 63; r >= 0; r-- {
+                               out0[i][gfBits-1-j] <<= 1
+                               out0[i][gfBits-1-j] |= (in[i*64+r] >> j) & 1
+                       }
+               }
+       }
+}
+
+func irrLoad(out *[2][gfBits]uint64, in []byte) {
+       irr := [sysT + 1]uint16{}
+
+       for i := 0; i < sysT; i++ {
+               irr[i] = loadGf(in[i*2:])
+       }
+
+       irr[sysT] = 1
+
+       v := [2]uint64{}
+       for i := 0; i < gfBits; i++ {
+               v[0] = 0
+               v[1] = 0
+
+               for j := 63; j >= 0; j-- {
+                       v[0] <<= 1
+                       v[0] |= uint64(irr[j]>>i) & 1
+               }
+               for j := sysT; j >= 64; j-- {
+                       v[1] <<= 1
+                       v[1] |= uint64(irr[j]>>i) & 1
+               }
+
+               out[0][i] = v[0]
+               out[1][i] = v[1]
+       }
+}
+
+// nolint:unparam
+// Public key generation. Generate the public key `pk`,
+// permutation `pi` and pivot element `pivots` based on the
+// secret key `sk` and permutation `perm` provided.
+// `pk` has `max(1 << GFBITS, SYS_N)` elements which is
+// 4096 for mceliece348864 and 8192 for mceliece8192128.
+// `sk` has `2 * SYS_T` elements and perm `1 << GFBITS`.
+func pkGen(pk *[pkNRows * pkRowBytes]byte, irr []byte, perm *[1 << gfBits]uint32, pi *[1 << gfBits]int16, pivots *uint64) bool {
+       const (
+               nblocksH = (sysN + 63) / 64
+               nblocksI = (pkNRows + 63) / 64
+
+               blockIdx = nblocksI - 1
+               tail     = pkNRows % 64
+       )
+       mat := [pkNRows][nblocksH]uint64{}
+       var mask uint64
+
+       irrInt := [2][gfBits]uint64{}
+
+       consts := [exponent][gfBits]uint64{}
+       eval := [exponent][gfBits]uint64{}
+       prod := [exponent][gfBits]uint64{}
+       tmp := [gfBits]uint64{}
+       list := [1 << gfBits]uint64{}
+
+       ops := [pkNRows][nblocksI]uint64{}
+
+       oneRow := [exponent]uint64{}
+
+       // compute the inverses
+       irrLoad(&irrInt, irr)
+       fft(&eval, &irrInt)
+       vecCopy(&prod[0], &eval[0])
+       for i := 1; i < exponent; i++ {
+               vecMul(&prod[i], &prod[i-1], &eval[i])
+       }
+       vecInv(&tmp, &prod[exponent-1])
+       for i := exponent - 2; i >= 0; i-- {
+               vecMul(&prod[i+1], &prod[i], &tmp)
+               vecMul(&tmp, &tmp, &eval[i+1])
+       }
+       vecCopy(&prod[0], &tmp)
+
+       // fill matrix
+       deBitSlicing(&list, &prod)
+       for i := uint64(0); i < (1 << gfBits); i++ {
+               list[i] <<= gfBits
+               list[i] |= i
+               list[i] |= (uint64(perm[i])) << 31
+       }
+       internal.UInt64Sort(list[:], 1<<gfBits)
+
+       for i := 1; i < (1 << gfBits); i++ {
+               if (list[i-1] >> 31) == (list[i] >> 31) {
+                       return false
+               }
+       }
+       toBitslicing2x(&consts, &prod, &list)
+
+       for i := 0; i < (1 << gfBits); i++ {
+               pi[i] = int16(list[i] & gfMask)
+       }
+
+       for j := 0; j < nblocksI; j++ {
+               for k := 0; k < gfBits; k++ {
+                       mat[k][j] = prod[j][k]
+               }
+       }
+
+       for i := 1; i < sysT; i++ {
+               for j := 0; j < nblocksI; j++ {
+                       vecMul(&prod[j], &prod[j], &consts[j])
+                       for k := 0; k < gfBits; k++ {
+                               mat[i*gfBits+k][j] = prod[j][k]
+                       }
+               }
+       }
+
+       // gaussian elimination to obtain an upper triangular matrix
+       // and keep track of the operations in ops
+
+       for i := 0; i < pkNRows; i++ {
+               for j := 0; j < nblocksI; j++ {
+                       ops[i][j] = 0
+               }
+       }
+       for i := 0; i < pkNRows; i++ {
+               ops[i][i/64] = 1
+               ops[i][i/64] <<= (i % 64)
+       }
+
+       column := [pkNRows]uint64{}
+       for i := 0; i < pkNRows; i++ {
+               column[i] = mat[i][blockIdx]
+       }
+
+       for row := 0; row < pkNRows; row++ {
+               i := row >> 6
+               j := row & 63
+
+               for k := row + 1; k < pkNRows; k++ {
+                       mask = mat[row][i] >> j
+                       mask &= 1
+                       mask -= 1
+
+                       for c := 0; c < nblocksI; c++ {
+                               mat[row][c] ^= mat[k][c] & mask
+                               ops[row][c] ^= ops[k][c] & mask
+                       }
+
+               }
+               // return if not systematic
+               if ((mat[row][i] >> j) & 1) == 0 {
+                       return false
+               }
+
+               for k := row + 1; k < pkNRows; k++ {
+                       mask = mat[k][i] >> j
+                       mask &= 1
+                       mask = -mask
+
+                       for c := 0; c < nblocksI; c++ {
+                               mat[k][c] ^= mat[row][c] & mask
+
+                               ops[k][c] ^= ops[row][c] & mask
+
+                       }
+               }
+       }
+
+       pkp := pk[:]
+
+       // computing the lineaer map required to obatin the systematic form
+
+       for row := pkNRows - 1; row >= 0; row-- {
+               for k := 0; k < row; k++ {
+                       mask = mat[k][row/64] >> (row & 63)
+                       mask &= 1
+                       mask = -mask
+
+                       for c := 0; c < nblocksI; c++ {
+                               ops[k][c] ^= ops[row][c] & mask
+                       }
+               }
+       }
+
+       // apply the linear map to the non-systematic part
+       for j := nblocksI; j < nblocksH; j++ {
+               for k := 0; k < gfBits; k++ {
+                       mat[k][j] = prod[j][k]
+               }
+       }
+
+       for i := 1; i < sysT; i++ {
+               for j := nblocksI; j < nblocksH; j++ {
+                       vecMul(&prod[j], &prod[j], &consts[j])
+                       for k := 0; k < gfBits; k++ {
+                               mat[i*gfBits+k][j] = prod[j][k]
+                       }
+               }
+       }
+
+       for i := 0; i < pkNRows; i++ {
+               mat[i][blockIdx] = column[i]
+       }
+
+       for row := 0; row < pkNRows; row++ {
+               for k := 0; k < nblocksH; k++ {
+                       oneRow[k] = 0
+               }
+
+               for c := 0; c < pkNRows; c++ {
+                       mask = ops[row][c>>6] >> (c & 63)
+                       mask &= 1
+                       mask = -mask
+
+                       for k := blockIdx; k < nblocksH; k++ {
+                               oneRow[k] ^= mat[c][k] & mask
+                       }
+               }
+
+               var k int
+               for k = blockIdx; k < nblocksH-1; k++ {
+
+                       oneRow[k] = (oneRow[k] >> tail) | (oneRow[k+1] << (64 - tail))
+
+                       store8(pkp, oneRow[k])
+                       pkp = pkp[8:]
+               }
+
+               oneRow[k] >>= tail
+
+               storeI(pkp, oneRow[k], pkRowBytes%8)
+
+               pkp[(pkRowBytes%8)-1] &= (1 << (pkNCols % 8)) - 1 // removing redundant bits
+
+               pkp = pkp[pkRowBytes%8:]
+       }
+
+       return true
+}
diff --git a/go/cm/enc/mceliece6960119-x25519/mceliece6960119/vec.go b/go/cm/enc/mceliece6960119-x25519/mceliece6960119/vec.go
new file mode 100644 (file)
index 0000000..74a7469
--- /dev/null
@@ -0,0 +1,132 @@
+// Code generated from vec.templ.go. DO NOT EDIT.
+
+// The following code is translated from the C `vec` Additional Implementation
+// from the NIST round 4 submission package.
+
+package mceliece6960119
+
+func vecMul(h, f, g *[gfBits]uint64) {
+       buf := [2*gfBits - 1]uint64{}
+
+       for i := 0; i < 2*gfBits-1; i++ {
+               buf[i] = 0
+       }
+
+       for i := 0; i < gfBits; i++ {
+               for j := 0; j < gfBits; j++ {
+                       buf[i+j] ^= f[i] & g[j]
+               }
+       }
+
+       for i := 2*gfBits - 2; i >= gfBits; i-- {
+
+               buf[i-gfBits+4] ^= buf[i]
+               buf[i-gfBits+3] ^= buf[i]
+               buf[i-gfBits+1] ^= buf[i]
+               buf[i-gfBits+0] ^= buf[i]
+
+       }
+
+       for i := 0; i < gfBits; i++ {
+               h[i] = buf[i]
+       }
+}
+
+// bitsliced field squarings
+func vecSq(out, in *[gfBits]uint64) {
+       result := [gfBits]uint64{}
+
+       t := in[11] ^ in[12]
+
+       result[0] = in[0] ^ in[11]
+       result[1] = in[7] ^ t
+       result[2] = in[1] ^ in[7]
+       result[3] = in[8] ^ t
+       result[4] = in[2] ^ in[7]
+       result[4] = result[4] ^ in[8]
+       result[4] = result[4] ^ t
+       result[5] = in[7] ^ in[9]
+       result[6] = in[3] ^ in[8]
+       result[6] = result[6] ^ in[9]
+       result[6] = result[6] ^ in[12]
+       result[7] = in[8] ^ in[10]
+       result[8] = in[4] ^ in[9]
+       result[8] = result[8] ^ in[10]
+       result[9] = in[9] ^ in[11]
+       result[10] = in[5] ^ in[10]
+       result[10] = result[10] ^ in[11]
+       result[11] = in[10] ^ in[12]
+       result[12] = in[6] ^ t
+
+       for i := 0; i < gfBits; i++ {
+               out[i] = result[i]
+       }
+}
+
+// bitsliced field inverses
+func vecInv(out, in *[gfBits]uint64) {
+       tmp11 := [gfBits]uint64{}
+       tmp1111 := [gfBits]uint64{}
+
+       vecCopy(out, in)
+
+       vecSq(out, out)
+       vecMul(&tmp11, out, in) // ^11
+
+       vecSq(out, &tmp11)
+       vecSq(out, out)
+       vecMul(&tmp1111, out, &tmp11) // ^1111
+
+       vecSq(out, &tmp1111)
+       vecSq(out, out)
+       vecSq(out, out)
+       vecSq(out, out)
+       vecMul(out, out, &tmp1111) // ^11111111
+
+       vecSq(out, out)
+       vecSq(out, out)
+       vecSq(out, out)
+       vecSq(out, out)
+       vecMul(out, out, &tmp1111) // ^111111111111
+
+       vecSq(out, out) // ^1111111111110
+}
+
+func vecSetBits(b uint64) uint64 {
+       ret := -b
+       return ret
+}
+
+func vecSet116b(v uint16) uint64 {
+       ret := uint64(v)
+       ret |= ret << 16
+       ret |= ret << 32
+
+       return ret
+}
+
+func vecCopy(out, in *[gfBits]uint64) {
+       for i := 0; i < gfBits; i++ {
+               out[i] = in[i]
+       }
+}
+
+func vecOrReduce(a *[gfBits]uint64) uint64 {
+       ret := a[0]
+       for i := 1; i < gfBits; i++ {
+               ret |= a[i]
+       }
+
+       return ret
+}
+
+func vecTestZ(a uint64) int {
+       a |= a >> 32
+       a |= a >> 16
+       a |= a >> 8
+       a |= a >> 4
+       a |= a >> 2
+       a |= a >> 1
+
+       return int((a & 1) ^ 1)
+}
index e296bd9e72a3a1159f740f51bbd3e06819a359722806bb5f511ccfcfe2f0928a..c5fe918dc806614c58000aa52f9f248649ecaa1f350fe29b66ae542c44477a67 100644 (file)
@@ -3,11 +3,19 @@ module go.cypherpunks.su/keks/cm
 go 1.24
 
 require (
+       github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a
        github.com/google/uuid v1.6.0
+       go.cypherpunks.su/balloon/v3 v3.0.0
        go.cypherpunks.su/gogost/v6 v6.1.0
+       go.cypherpunks.su/keks v0.0.0-00010101000000-000000000000
+       golang.org/x/crypto v0.32.0
+       golang.org/x/sys v0.29.0
+       golang.org/x/term v0.28.0
 )
 
 require (
-       go.cypherpunks.su/balloon/v3 v3.0.0 // indirect
-       golang.org/x/crypto v0.32.0 // indirect
+       github.com/mitchellh/mapstructure v1.5.0 // indirect
+       go.cypherpunks.su/tai64n/v4 v4.1.0 // indirect
 )
+
+replace go.cypherpunks.su/keks => ../
index 55a7d0f465c95ce0a2fd01bb4fc00b2b13a187fff7217a41858646f68a4c391e..b05aeaef9b43b2bb0bbe7adf727f32128cb639436d47ef470fd5804745bbf47e 100644 (file)
@@ -1,6 +1,18 @@
+github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a h1:clYxJ3Os0EQUKDDVU8M0oipllX0EkuFNBfhVQuIfyF0=
+github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a/go.mod h1:z/9Ck1EDixEbBbZ2KH2qNHekEmDLTOZ+FyoIPWWSVOI=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+go.cypherpunks.su/balloon/v3 v3.0.0 h1:80JUfOvjEgeuQlZ8biZarbuld0T9L/6gbC2DAZAZncI=
 go.cypherpunks.su/balloon/v3 v3.0.0/go.mod h1:ftUPgriajbLsU16feNNHht6cuOwxCK6MGnDK3lLQhgM=
 go.cypherpunks.su/gogost/v6 v6.1.0 h1:RJHFxDZ2j/TIfHXGn4AG0fTDg19GEX/oVFAgMvLCIPM=
 go.cypherpunks.su/gogost/v6 v6.1.0/go.mod h1:cj9i0r80PN7jrwMqBAWhaY8JetCeg4x5jjnZsVRkaPI=
+go.cypherpunks.su/tai64n/v4 v4.1.0 h1:jW0EyklKXpSy9DSFMcDbu7XuLlMkn6kkpNWiMG6UT5c=
+go.cypherpunks.su/tai64n/v4 v4.1.0/go.mod h1:/uKUdhLOy8UciRKpapPaFXSOoa/SiXjs3XsDDpAz7OA=
+golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
 golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
+golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
index 7459fc36bf4bba55270c74ba214848d96887c82e83a68deea609fd32c38d10d1..3942c7b5e6953cca6c3d4788346adbd74d5574d945b174f20addb0a529cbd6d0 100644 (file)
@@ -23,8 +23,8 @@ import (
        "go.cypherpunks.su/gogost/v6/gost34112012512"
        "golang.org/x/crypto/blake2b"
 
-       ed25519blake2b "go.cypherpunks.su/keks/cm/ed25519-blake2b"
-       "go.cypherpunks.su/keks/cm/gost"
+       cmblake2b "go.cypherpunks.su/keks/cm/hash/blake2b"
+       "go.cypherpunks.su/keks/cm/hash/gost"
        "go.cypherpunks.su/keks/cm/hash/merkle"
 )
 
@@ -56,14 +56,14 @@ func ByName(name string) hash.Hash {
        case Streebog512Merkle, gost.GOST3410512CMerkle:
                return gost.NewMerkleHasher(gost34112012512.New,
                        merkle.DefaultChunkLen, runtime.NumCPU())
-       case BLAKE2b, ed25519blake2b.Ed25519BLAKE2b, ed25519blake2b.Ed25519PhBLAKE2b:
+       case BLAKE2b, cmblake2b.Ed25519BLAKE2b, cmblake2b.Ed25519PhBLAKE2b:
                h, err := blake2b.New512(nil)
                if err != nil {
                        panic(err)
                }
                return h
-       case BLAKE2bMerkle, ed25519blake2b.Ed25519PhBLAKE2bMerkle:
-               return ed25519blake2b.NewMerkleHasher(
+       case BLAKE2bMerkle, cmblake2b.Ed25519PhBLAKE2bMerkle:
+               return cmblake2b.NewMerkleHasher(
                        merkle.DefaultChunkLen, runtime.NumCPU())
        case BLAKE2b256:
                h, err := blake2b.New256(nil)
diff --git a/go/cm/hash/gost/algo.go b/go/cm/hash/gost/algo.go
new file mode 100644 (file)
index 0000000..910c9bb
--- /dev/null
@@ -0,0 +1,8 @@
+package gost
+
+const (
+       GOST3410256A       = "gost3410-256A"
+       GOST3410512C       = "gost3410-512C"
+       GOST3410256AMerkle = "gost3410-256A-merkle"
+       GOST3410512CMerkle = "gost3410-512C-merkle"
+)
similarity index 90%
rename from go/cm/gost/hasher.go
rename to go/cm/hash/gost/hasher.go
index fcd729e914b81524c8971b719e0e4d9b1402bc74d72e49f34ff0ca065b05de7d..4ffae5bcd88bec38cf4465d61b1af22ebc73b9d459290cf3ac0189cf7bbe22c0 100644 (file)
@@ -21,11 +21,6 @@ import (
        "go.cypherpunks.su/keks/cm/hash/merkle"
 )
 
-const (
-       GOST3410256AMerkle = "gost3410-256A-merkle"
-       GOST3410512CMerkle = "gost3410-512C-merkle"
-)
-
 func NewMerkleHasher(h func() hash.Hash, chunkLen, workers int) hash.Hash {
        return merkle.NewHasherPrefixed(h, chunkLen, workers)
 }
diff --git a/go/cm/hash/magic.go b/go/cm/hash/magic.go
new file mode 100644 (file)
index 0000000..dd385bb
--- /dev/null
@@ -0,0 +1,5 @@
+package hash
+
+import "go.cypherpunks.su/keks"
+
+const Magic = keks.Magic("cm/hashed")
diff --git a/go/cm/mceliece6960119-x25519/SOURCE b/go/cm/mceliece6960119-x25519/SOURCE
deleted file mode 100644 (file)
index 4fa5970..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-https://github.com/cloudflare/circl/pull/378
-https://github.com/cloudflare/circl.git
-7dfc396c96830ed3601ace705e1612b9bcc447f9
diff --git a/go/cm/sign/ed25519-blake2b/README b/go/cm/sign/ed25519-blake2b/README
new file mode 100644 (file)
index 0000000..24a6208
--- /dev/null
@@ -0,0 +1,4 @@
+Unfortunately native crypto/internal/ed25519 is not flexible enough and
+does not give ability to use different hash in Ed25519. So here is the
+copied implementation from Go 1.24 with all dependencies and replaced
+SHA2-512 with BLAKE2b-512.
diff --git a/go/cm/sign/ed25519-blake2b/algo.go b/go/cm/sign/ed25519-blake2b/algo.go
new file mode 100644 (file)
index 0000000..36b3f3f
--- /dev/null
@@ -0,0 +1,7 @@
+package ed25519blake2b
+
+const (
+       Ed25519BLAKE2b         = "ed25519-blake2b"
+       Ed25519PhBLAKE2b       = "ed25519ph-blake2b"
+       Ed25519PhBLAKE2bMerkle = "ed25519ph-blake2b-merkle"
+)
diff --git a/go/cm/sign/ed25519-blake2b/ed25519/ed25519.go b/go/cm/sign/ed25519-blake2b/ed25519/ed25519.go
new file mode 100644 (file)
index 0000000..db4d0ae
--- /dev/null
@@ -0,0 +1,325 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ed25519
+
+import (
+       "bytes"
+       "crypto/rand"
+       "errors"
+       "strconv"
+
+       "golang.org/x/crypto/blake2b"
+
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519"
+)
+
+// See https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/ for the
+// components of the keys and the moving parts of the algorithm.
+
+const (
+       seedSize       = 32
+       publicKeySize  = 32
+       privateKeySize = seedSize + publicKeySize
+       signatureSize  = 64
+)
+
+type PrivateKey struct {
+       seed   [seedSize]byte
+       pub    [publicKeySize]byte
+       s      edwards25519.Scalar
+       prefix [blake2b.Size / 2]byte
+}
+
+func (priv *PrivateKey) Bytes() []byte {
+       k := make([]byte, 0, privateKeySize)
+       k = append(k, priv.seed[:]...)
+       k = append(k, priv.pub[:]...)
+       return k
+}
+
+func (priv *PrivateKey) Seed() []byte {
+       seed := priv.seed
+       return seed[:]
+}
+
+func (priv *PrivateKey) PublicKey() []byte {
+       pub := priv.pub
+       return pub[:]
+}
+
+type PublicKey struct {
+       a      edwards25519.Point
+       aBytes [32]byte
+}
+
+func (pub *PublicKey) Bytes() []byte {
+       a := pub.aBytes
+       return a[:]
+}
+
+// GenerateKey generates a new Ed25519 private key pair.
+func GenerateKey() (*PrivateKey, error) {
+       priv := &PrivateKey{}
+       return generateKey(priv)
+}
+
+func generateKey(priv *PrivateKey) (*PrivateKey, error) {
+       rand.Read(priv.seed[:])
+       precomputePrivateKey(priv)
+       return priv, nil
+}
+
+func NewPrivateKeyFromSeed(seed []byte) (*PrivateKey, error) {
+       priv := &PrivateKey{}
+       return newPrivateKeyFromSeed(priv, seed)
+}
+
+func newPrivateKeyFromSeed(priv *PrivateKey, seed []byte) (*PrivateKey, error) {
+       if l := len(seed); l != seedSize {
+               return nil, errors.New("ed25519: bad seed length: " + strconv.Itoa(l))
+       }
+       copy(priv.seed[:], seed)
+       precomputePrivateKey(priv)
+       return priv, nil
+}
+
+func precomputePrivateKey(priv *PrivateKey) {
+       hs, err := blake2b.New512(nil)
+       if err != nil {
+               panic(err)
+       }
+       hs.Write(priv.seed[:])
+       h := hs.Sum(make([]byte, 0, blake2b.Size))
+
+       s, err := priv.s.SetBytesWithClamping(h[:32])
+       if err != nil {
+               panic("ed25519: internal error: setting scalar failed")
+       }
+       A := (&edwards25519.Point{}).ScalarBaseMult(s)
+       copy(priv.pub[:], A.Bytes())
+
+       copy(priv.prefix[:], h[32:])
+}
+
+func NewPrivateKey(priv []byte) (*PrivateKey, error) {
+       p := &PrivateKey{}
+       return newPrivateKey(p, priv)
+}
+
+func newPrivateKey(priv *PrivateKey, privBytes []byte) (*PrivateKey, error) {
+       if l := len(privBytes); l != privateKeySize {
+               return nil, errors.New("ed25519: bad private key length: " + strconv.Itoa(l))
+       }
+
+       copy(priv.seed[:], privBytes[:32])
+
+       hs, err := blake2b.New512(nil)
+       if err != nil {
+               panic(err)
+       }
+       hs.Write(priv.seed[:])
+       h := hs.Sum(make([]byte, 0, blake2b.Size))
+
+       if _, err := priv.s.SetBytesWithClamping(h[:32]); err != nil {
+               panic("ed25519: internal error: setting scalar failed")
+       }
+       // Note that we are not decompressing the public key point here,
+       // because it takes > 20% of the time of a signature generation.
+       // Signing doesn't use it as a point anyway.
+       copy(priv.pub[:], privBytes[32:])
+
+       copy(priv.prefix[:], h[32:])
+
+       return priv, nil
+}
+
+func NewPublicKey(pub []byte) (*PublicKey, error) {
+       p := &PublicKey{}
+       return newPublicKey(p, pub)
+}
+
+func newPublicKey(pub *PublicKey, pubBytes []byte) (*PublicKey, error) {
+       if l := len(pubBytes); l != publicKeySize {
+               return nil, errors.New("ed25519: bad public key length: " + strconv.Itoa(l))
+       }
+       // SetBytes checks that the point is on the curve.
+       if _, err := pub.a.SetBytes(pubBytes); err != nil {
+               return nil, errors.New("ed25519: bad public key")
+       }
+       copy(pub.aBytes[:], pubBytes)
+       return pub, nil
+}
+
+// Domain separation prefixes used to disambiguate Ed25519/Ed25519ph/Ed25519ctx.
+// See RFC 8032, Section 2 and Section 5.1.
+const (
+       // domPrefixPure is empty for pure Ed25519.
+       domPrefixPure = ""
+       // domPrefixPh is dom2(phflag=1) for Ed25519ph. It must be followed by the
+       // uint8-length prefixed context.
+       domPrefixPh = "SigEd25519 no Ed25519 collisions\x01"
+       // domPrefixCtx is dom2(phflag=0) for Ed25519ctx. It must be followed by the
+       // uint8-length prefixed context.
+       domPrefixCtx = "SigEd25519 no Ed25519 collisions\x00"
+)
+
+func Sign(priv *PrivateKey, message []byte) []byte {
+       // Outline the function body so that the returned signature can be
+       // stack-allocated.
+       signature := make([]byte, signatureSize)
+       return sign(signature, priv, message)
+}
+
+func sign(signature []byte, priv *PrivateKey, message []byte) []byte {
+       return signWithDom(signature, priv, message, domPrefixPure, "")
+}
+
+func SignPH(priv *PrivateKey, message []byte, context string) ([]byte, error) {
+       // Outline the function body so that the returned signature can be
+       // stack-allocated.
+       signature := make([]byte, signatureSize)
+       return signPH(signature, priv, message, context)
+}
+
+func signPH(signature []byte, priv *PrivateKey, message []byte, context string) ([]byte, error) {
+       if l := len(message); l != blake2b.Size {
+               return nil, errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
+       }
+       if l := len(context); l > 255 {
+               return nil, errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
+       }
+       return signWithDom(signature, priv, message, domPrefixPh, context), nil
+}
+
+func SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) {
+       // Outline the function body so that the returned signature can be
+       // stack-allocated.
+       signature := make([]byte, signatureSize)
+       return signCtx(signature, priv, message, context)
+}
+
+func signCtx(signature []byte, priv *PrivateKey, message []byte, context string) ([]byte, error) {
+       // Note that per RFC 8032, Section 5.1, the context SHOULD NOT be empty.
+       if l := len(context); l > 255 {
+               return nil, errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
+       }
+       return signWithDom(signature, priv, message, domPrefixCtx, context), nil
+}
+
+func signWithDom(signature []byte, priv *PrivateKey, message []byte, domPrefix, context string) []byte {
+       mh, err := blake2b.New512(nil)
+       if err != nil {
+               panic(err)
+       }
+       if domPrefix != domPrefixPure {
+               mh.Write([]byte(domPrefix))
+               mh.Write([]byte{byte(len(context))})
+               mh.Write([]byte(context))
+       }
+       mh.Write(priv.prefix[:])
+       mh.Write(message)
+       messageDigest := make([]byte, 0, blake2b.Size)
+       messageDigest = mh.Sum(messageDigest)
+       r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
+       if err != nil {
+               panic("ed25519: internal error: setting scalar failed")
+       }
+
+       R := (&edwards25519.Point{}).ScalarBaseMult(r)
+
+       kh, err := blake2b.New512(nil)
+       if err != nil {
+               panic(err)
+       }
+       if domPrefix != domPrefixPure {
+               kh.Write([]byte(domPrefix))
+               kh.Write([]byte{byte(len(context))})
+               kh.Write([]byte(context))
+       }
+       kh.Write(R.Bytes())
+       kh.Write(priv.pub[:])
+       kh.Write(message)
+       hramDigest := make([]byte, 0, blake2b.Size)
+       hramDigest = kh.Sum(hramDigest)
+       k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
+       if err != nil {
+               panic("ed25519: internal error: setting scalar failed")
+       }
+
+       S := edwards25519.NewScalar().MultiplyAdd(k, &priv.s, r)
+
+       copy(signature[:32], R.Bytes())
+       copy(signature[32:], S.Bytes())
+
+       return signature
+}
+
+func Verify(pub *PublicKey, message, sig []byte) error {
+       return verify(pub, message, sig)
+}
+
+func verify(pub *PublicKey, message, sig []byte) error {
+       return verifyWithDom(pub, message, sig, domPrefixPure, "")
+}
+
+func VerifyPH(pub *PublicKey, message, sig []byte, context string) error {
+       if l := len(message); l != blake2b.Size {
+               return errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
+       }
+       if l := len(context); l > 255 {
+               return errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
+       }
+       return verifyWithDom(pub, message, sig, domPrefixPh, context)
+}
+
+func VerifyCtx(pub *PublicKey, message, sig []byte, context string) error {
+       if l := len(context); l > 255 {
+               return errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
+       }
+       return verifyWithDom(pub, message, sig, domPrefixCtx, context)
+}
+
+func verifyWithDom(pub *PublicKey, message, sig []byte, domPrefix, context string) error {
+       if l := len(sig); l != signatureSize {
+               return errors.New("ed25519: bad signature length: " + strconv.Itoa(l))
+       }
+
+       if sig[63]&224 != 0 {
+               return errors.New("ed25519: invalid signature")
+       }
+
+       kh, err := blake2b.New512(nil)
+       if err != nil {
+               panic(err)
+       }
+       if domPrefix != domPrefixPure {
+               kh.Write([]byte(domPrefix))
+               kh.Write([]byte{byte(len(context))})
+               kh.Write([]byte(context))
+       }
+       kh.Write(sig[:32])
+       kh.Write(pub.aBytes[:])
+       kh.Write(message)
+       hramDigest := make([]byte, 0, blake2b.Size)
+       hramDigest = kh.Sum(hramDigest)
+       k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
+       if err != nil {
+               panic("ed25519: internal error: setting scalar failed")
+       }
+
+       S, err := edwards25519.NewScalar().SetCanonicalBytes(sig[32:])
+       if err != nil {
+               return errors.New("ed25519: invalid signature")
+       }
+
+       // [S]B = R + [k]A --> [k](-A) + [S]B = R
+       minusA := (&edwards25519.Point{}).Negate(&pub.a)
+       R := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(k, minusA, S)
+
+       if !bytes.Equal(sig[:32], R.Bytes()) {
+               return errors.New("ed25519: invalid signature")
+       }
+       return nil
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/alias/alias.go b/go/cm/sign/ed25519-blake2b/edwards25519/alias/alias.go
new file mode 100644 (file)
index 0000000..cd6dee9
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package alias implements memory aliasing tests.
+// This code also exists as golang.org/x/crypto/internal/alias.
+package alias
+
+import "unsafe"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+       return len(x) > 0 && len(y) > 0 &&
+               uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+               uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+       if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+               return false
+       }
+       return AnyOverlap(x, y)
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/byteorder/byteorder.go b/go/cm/sign/ed25519-blake2b/edwards25519/byteorder/byteorder.go
new file mode 100644 (file)
index 0000000..acf4f32
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package byteorder provides functions for decoding and encoding
+// little and big endian integer types from/to byte slices.
+package byteorder
+
+func LEUint16(b []byte) uint16 {
+       _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func LEPutUint16(b []byte, v uint16) {
+       _ = b[1] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+}
+
+func LEAppendUint16(b []byte, v uint16) []byte {
+       return append(b,
+               byte(v),
+               byte(v>>8),
+       )
+}
+
+func LEUint32(b []byte) uint32 {
+       _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func LEPutUint32(b []byte, v uint32) {
+       _ = b[3] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+       b[2] = byte(v >> 16)
+       b[3] = byte(v >> 24)
+}
+
+func LEAppendUint32(b []byte, v uint32) []byte {
+       return append(b,
+               byte(v),
+               byte(v>>8),
+               byte(v>>16),
+               byte(v>>24),
+       )
+}
+
+func LEUint64(b []byte) uint64 {
+       _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+               uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func LEPutUint64(b []byte, v uint64) {
+       _ = b[7] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v)
+       b[1] = byte(v >> 8)
+       b[2] = byte(v >> 16)
+       b[3] = byte(v >> 24)
+       b[4] = byte(v >> 32)
+       b[5] = byte(v >> 40)
+       b[6] = byte(v >> 48)
+       b[7] = byte(v >> 56)
+}
+
+func LEAppendUint64(b []byte, v uint64) []byte {
+       return append(b,
+               byte(v),
+               byte(v>>8),
+               byte(v>>16),
+               byte(v>>24),
+               byte(v>>32),
+               byte(v>>40),
+               byte(v>>48),
+               byte(v>>56),
+       )
+}
+
+func BEUint16(b []byte) uint16 {
+       _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint16(b[1]) | uint16(b[0])<<8
+}
+
+func BEPutUint16(b []byte, v uint16) {
+       _ = b[1] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v >> 8)
+       b[1] = byte(v)
+}
+
+func BEAppendUint16(b []byte, v uint16) []byte {
+       return append(b,
+               byte(v>>8),
+               byte(v),
+       )
+}
+
+func BEUint32(b []byte) uint32 {
+       _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func BEPutUint32(b []byte, v uint32) {
+       _ = b[3] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v >> 24)
+       b[1] = byte(v >> 16)
+       b[2] = byte(v >> 8)
+       b[3] = byte(v)
+}
+
+func BEAppendUint32(b []byte, v uint32) []byte {
+       return append(b,
+               byte(v>>24),
+               byte(v>>16),
+               byte(v>>8),
+               byte(v),
+       )
+}
+
+func BEUint64(b []byte) uint64 {
+       _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+       return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+               uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func BEPutUint64(b []byte, v uint64) {
+       _ = b[7] // early bounds check to guarantee safety of writes below
+       b[0] = byte(v >> 56)
+       b[1] = byte(v >> 48)
+       b[2] = byte(v >> 40)
+       b[3] = byte(v >> 32)
+       b[4] = byte(v >> 24)
+       b[5] = byte(v >> 16)
+       b[6] = byte(v >> 8)
+       b[7] = byte(v)
+}
+
+func BEAppendUint64(b []byte, v uint64) []byte {
+       return append(b,
+               byte(v>>56),
+               byte(v>>48),
+               byte(v>>40),
+               byte(v>>32),
+               byte(v>>24),
+               byte(v>>16),
+               byte(v>>8),
+               byte(v),
+       )
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/doc.go b/go/cm/sign/ed25519-blake2b/edwards25519/doc.go
new file mode 100644 (file)
index 0000000..aec810c
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package edwards25519 implements group logic for the twisted Edwards curve
+//
+//     -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
+//
+// This is better known as the Edwards curve equivalent to Curve25519, and is
+// the curve used by the Ed25519 signature scheme.
+//
+// Most users don't need this package, and should instead use crypto/ed25519 for
+// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
+// github.com/gtank/ristretto255 for prime order group logic.
+//
+// However, developers who do need to interact with low-level edwards25519
+// operations can use filippo.io/edwards25519, an extended version of this
+// package repackaged as an importable module.
+//
+// (Note that filippo.io/edwards25519 and github.com/gtank/ristretto255 are not
+// maintained by the Go team and are not covered by the Go 1 Compatibility Promise.)
+package edwards25519
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/edwards25519.go b/go/cm/sign/ed25519-blake2b/edwards25519/edwards25519.go
new file mode 100644 (file)
index 0000000..6d19b86
--- /dev/null
@@ -0,0 +1,430 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+       "errors"
+
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/field"
+)
+
+// Point types.
+
+type projP1xP1 struct {
+       X, Y, Z, T field.Element
+}
+
+type projP2 struct {
+       X, Y, Z field.Element
+}
+
+// Point represents a point on the edwards25519 curve.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is NOT valid, and it may be used only as a receiver.
+type Point struct {
+       // Make the type not comparable (i.e. used with == or as a map key), as
+       // equivalent points can be represented by different Go values.
+       _ incomparable
+
+       // The point is internally represented in extended coordinates (X, Y, Z, T)
+       // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522.
+       x, y, z, t field.Element
+}
+
+type incomparable [0]func()
+
+func checkInitialized(points ...*Point) {
+       for _, p := range points {
+               if p.x == (field.Element{}) && p.y == (field.Element{}) {
+                       panic("edwards25519: use of uninitialized Point")
+               }
+       }
+}
+
+type projCached struct {
+       YplusX, YminusX, Z, T2d field.Element
+}
+
+type affineCached struct {
+       YplusX, YminusX, T2d field.Element
+}
+
+// Constructors.
+
+func (v *projP2) Zero() *projP2 {
+       v.X.Zero()
+       v.Y.One()
+       v.Z.One()
+       return v
+}
+
+// identity is the point at infinity.
+var identity, _ = new(Point).SetBytes([]byte{
+       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+})
+
+// NewIdentityPoint returns a new Point set to the identity.
+func NewIdentityPoint() *Point {
+       return new(Point).Set(identity)
+}
+
+// generator is the canonical curve basepoint. See TestGenerator for the
+// correspondence of this encoding with the values in RFC 8032.
+var generator, _ = new(Point).SetBytes([]byte{
+       0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+       0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+       0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+       0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+})
+
+// NewGeneratorPoint returns a new Point set to the canonical generator.
+func NewGeneratorPoint() *Point {
+       return new(Point).Set(generator)
+}
+
+func (v *projCached) Zero() *projCached {
+       v.YplusX.One()
+       v.YminusX.One()
+       v.Z.One()
+       v.T2d.Zero()
+       return v
+}
+
+func (v *affineCached) Zero() *affineCached {
+       v.YplusX.One()
+       v.YminusX.One()
+       v.T2d.Zero()
+       return v
+}
+
+// Assignments.
+
+// Set sets v = u, and returns v.
+func (v *Point) Set(u *Point) *Point {
+       *v = *u
+       return v
+}
+
+// Encoding.
+
+// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
+// Section 5.1.2.
+func (v *Point) Bytes() []byte {
+       // This function is outlined to make the allocations inline in the caller
+       // rather than happen on the heap.
+       var buf [32]byte
+       return v.bytes(&buf)
+}
+
+func (v *Point) bytes(buf *[32]byte) []byte {
+       checkInitialized(v)
+
+       var zInv, x, y field.Element
+       zInv.Invert(&v.z)       // zInv = 1 / Z
+       x.Multiply(&v.x, &zInv) // x = X / Z
+       y.Multiply(&v.y, &zInv) // y = Y / Z
+
+       out := copyFieldElement(buf, &y)
+       out[31] |= byte(x.IsNegative() << 7)
+       return out
+}
+
+var feOne = new(field.Element).One()
+
+// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not
+// represent a valid point on the curve, SetBytes returns nil and an error and
+// the receiver is unchanged. Otherwise, SetBytes returns v.
+//
+// Note that SetBytes accepts all non-canonical encodings of valid points.
+// That is, it follows decoding rules that match most implementations in
+// the ecosystem rather than RFC 8032.
+func (v *Point) SetBytes(x []byte) (*Point, error) {
+       // Specifically, the non-canonical encodings that are accepted are
+       //   1) the ones where the field element is not reduced (see the
+       //      (*field.Element).SetBytes docs) and
+       //   2) the ones where the x-coordinate is zero and the sign bit is set.
+       //
+       // Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am,
+       // specifically the "Canonical A, R" section.
+
+       y, err := new(field.Element).SetBytes(x)
+       if err != nil {
+               return nil, errors.New("edwards25519: invalid point encoding length")
+       }
+
+       // -x² + y² = 1 + dx²y²
+       // x² + dx²y² = x²(dy² + 1) = y² - 1
+       // x² = (y² - 1) / (dy² + 1)
+
+       // u = y² - 1
+       y2 := new(field.Element).Square(y)
+       u := new(field.Element).Subtract(y2, feOne)
+
+       // v = dy² + 1
+       vv := new(field.Element).Multiply(y2, d)
+       vv = vv.Add(vv, feOne)
+
+       // x = +√(u/v)
+       xx, wasSquare := new(field.Element).SqrtRatio(u, vv)
+       if wasSquare == 0 {
+               return nil, errors.New("edwards25519: invalid point encoding")
+       }
+
+       // Select the negative square root if the sign bit is set.
+       xxNeg := new(field.Element).Negate(xx)
+       xx = xx.Select(xxNeg, xx, int(x[31]>>7))
+
+       v.x.Set(xx)
+       v.y.Set(y)
+       v.z.One()
+       v.t.Multiply(xx, y) // xy = T / Z
+
+       return v, nil
+}
+
+func copyFieldElement(buf *[32]byte, v *field.Element) []byte {
+       copy(buf[:], v.Bytes())
+       return buf[:]
+}
+
+// Conversions.
+
+func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 {
+       v.X.Multiply(&p.X, &p.T)
+       v.Y.Multiply(&p.Y, &p.Z)
+       v.Z.Multiply(&p.Z, &p.T)
+       return v
+}
+
+func (v *projP2) FromP3(p *Point) *projP2 {
+       v.X.Set(&p.x)
+       v.Y.Set(&p.y)
+       v.Z.Set(&p.z)
+       return v
+}
+
+func (v *Point) fromP1xP1(p *projP1xP1) *Point {
+       v.x.Multiply(&p.X, &p.T)
+       v.y.Multiply(&p.Y, &p.Z)
+       v.z.Multiply(&p.Z, &p.T)
+       v.t.Multiply(&p.X, &p.Y)
+       return v
+}
+
+func (v *Point) fromP2(p *projP2) *Point {
+       v.x.Multiply(&p.X, &p.Z)
+       v.y.Multiply(&p.Y, &p.Z)
+       v.z.Square(&p.Z)
+       v.t.Multiply(&p.X, &p.Y)
+       return v
+}
+
+// d is a constant in the curve equation.
+var d, _ = new(field.Element).SetBytes([]byte{
+       0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
+       0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
+       0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
+       0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52,
+})
+var d2 = new(field.Element).Add(d, d)
+
+func (v *projCached) FromP3(p *Point) *projCached {
+       v.YplusX.Add(&p.y, &p.x)
+       v.YminusX.Subtract(&p.y, &p.x)
+       v.Z.Set(&p.z)
+       v.T2d.Multiply(&p.t, d2)
+       return v
+}
+
+func (v *affineCached) FromP3(p *Point) *affineCached {
+       v.YplusX.Add(&p.y, &p.x)
+       v.YminusX.Subtract(&p.y, &p.x)
+       v.T2d.Multiply(&p.t, d2)
+
+       var invZ field.Element
+       invZ.Invert(&p.z)
+       v.YplusX.Multiply(&v.YplusX, &invZ)
+       v.YminusX.Multiply(&v.YminusX, &invZ)
+       v.T2d.Multiply(&v.T2d, &invZ)
+       return v
+}
+
+// (Re)addition and subtraction.
+
+// Add sets v = p + q, and returns v.
+func (v *Point) Add(p, q *Point) *Point {
+       checkInitialized(p, q)
+       qCached := new(projCached).FromP3(q)
+       result := new(projP1xP1).Add(p, qCached)
+       return v.fromP1xP1(result)
+}
+
+// Subtract sets v = p - q, and returns v.
+func (v *Point) Subtract(p, q *Point) *Point {
+       checkInitialized(p, q)
+       qCached := new(projCached).FromP3(q)
+       result := new(projP1xP1).Sub(p, qCached)
+       return v.fromP1xP1(result)
+}
+
+func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 {
+       var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
+
+       YplusX.Add(&p.y, &p.x)
+       YminusX.Subtract(&p.y, &p.x)
+
+       PP.Multiply(&YplusX, &q.YplusX)
+       MM.Multiply(&YminusX, &q.YminusX)
+       TT2d.Multiply(&p.t, &q.T2d)
+       ZZ2.Multiply(&p.z, &q.Z)
+
+       ZZ2.Add(&ZZ2, &ZZ2)
+
+       v.X.Subtract(&PP, &MM)
+       v.Y.Add(&PP, &MM)
+       v.Z.Add(&ZZ2, &TT2d)
+       v.T.Subtract(&ZZ2, &TT2d)
+       return v
+}
+
+func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 {
+       var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
+
+       YplusX.Add(&p.y, &p.x)
+       YminusX.Subtract(&p.y, &p.x)
+
+       PP.Multiply(&YplusX, &q.YminusX) // flipped sign
+       MM.Multiply(&YminusX, &q.YplusX) // flipped sign
+       TT2d.Multiply(&p.t, &q.T2d)
+       ZZ2.Multiply(&p.z, &q.Z)
+
+       ZZ2.Add(&ZZ2, &ZZ2)
+
+       v.X.Subtract(&PP, &MM)
+       v.Y.Add(&PP, &MM)
+       v.Z.Subtract(&ZZ2, &TT2d) // flipped sign
+       v.T.Add(&ZZ2, &TT2d)      // flipped sign
+       return v
+}
+
+func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 {
+       var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
+
+       YplusX.Add(&p.y, &p.x)
+       YminusX.Subtract(&p.y, &p.x)
+
+       PP.Multiply(&YplusX, &q.YplusX)
+       MM.Multiply(&YminusX, &q.YminusX)
+       TT2d.Multiply(&p.t, &q.T2d)
+
+       Z2.Add(&p.z, &p.z)
+
+       v.X.Subtract(&PP, &MM)
+       v.Y.Add(&PP, &MM)
+       v.Z.Add(&Z2, &TT2d)
+       v.T.Subtract(&Z2, &TT2d)
+       return v
+}
+
+func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 {
+       var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
+
+       YplusX.Add(&p.y, &p.x)
+       YminusX.Subtract(&p.y, &p.x)
+
+       PP.Multiply(&YplusX, &q.YminusX) // flipped sign
+       MM.Multiply(&YminusX, &q.YplusX) // flipped sign
+       TT2d.Multiply(&p.t, &q.T2d)
+
+       Z2.Add(&p.z, &p.z)
+
+       v.X.Subtract(&PP, &MM)
+       v.Y.Add(&PP, &MM)
+       v.Z.Subtract(&Z2, &TT2d) // flipped sign
+       v.T.Add(&Z2, &TT2d)      // flipped sign
+       return v
+}
+
+// Doubling.
+
+func (v *projP1xP1) Double(p *projP2) *projP1xP1 {
+       var XX, YY, ZZ2, XplusYsq field.Element
+
+       XX.Square(&p.X)
+       YY.Square(&p.Y)
+       ZZ2.Square(&p.Z)
+       ZZ2.Add(&ZZ2, &ZZ2)
+       XplusYsq.Add(&p.X, &p.Y)
+       XplusYsq.Square(&XplusYsq)
+
+       v.Y.Add(&YY, &XX)
+       v.Z.Subtract(&YY, &XX)
+
+       v.X.Subtract(&XplusYsq, &v.Y)
+       v.T.Subtract(&ZZ2, &v.Z)
+       return v
+}
+
+// Negation.
+
+// Negate sets v = -p, and returns v.
+func (v *Point) Negate(p *Point) *Point {
+       checkInitialized(p)
+       v.x.Negate(&p.x)
+       v.y.Set(&p.y)
+       v.z.Set(&p.z)
+       v.t.Negate(&p.t)
+       return v
+}
+
+// Equal returns 1 if v is equivalent to u, and 0 otherwise.
+func (v *Point) Equal(u *Point) int {
+       checkInitialized(v, u)
+
+       var t1, t2, t3, t4 field.Element
+       t1.Multiply(&v.x, &u.z)
+       t2.Multiply(&u.x, &v.z)
+       t3.Multiply(&v.y, &u.z)
+       t4.Multiply(&u.y, &v.z)
+
+       return t1.Equal(&t2) & t3.Equal(&t4)
+}
+
+// Constant-time operations
+
+// Select sets v to a if cond == 1 and to b if cond == 0.
+func (v *projCached) Select(a, b *projCached, cond int) *projCached {
+       v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
+       v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
+       v.Z.Select(&a.Z, &b.Z, cond)
+       v.T2d.Select(&a.T2d, &b.T2d, cond)
+       return v
+}
+
+// Select sets v to a if cond == 1 and to b if cond == 0.
+func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached {
+       v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
+       v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
+       v.T2d.Select(&a.T2d, &b.T2d, cond)
+       return v
+}
+
+// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
+func (v *projCached) CondNeg(cond int) *projCached {
+       v.YplusX.Swap(&v.YminusX, cond)
+       v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
+       return v
+}
+
+// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
+func (v *affineCached) CondNeg(cond int) *affineCached {
+       v.YplusX.Swap(&v.YminusX, cond)
+       v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
+       return v
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/fe_amd64_asm.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/fe_amd64_asm.go
new file mode 100644 (file)
index 0000000..fe6abb0
--- /dev/null
@@ -0,0 +1,294 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+
+       . "github.com/mmcloughlin/avo/build"
+       . "github.com/mmcloughlin/avo/gotypes"
+       . "github.com/mmcloughlin/avo/operand"
+       . "github.com/mmcloughlin/avo/reg"
+)
+
+//go:generate go run . -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field
+
+func main() {
+       Package("go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/field")
+       ConstraintExpr("!purego")
+       feMul()
+       feSquare()
+       Generate()
+}
+
+type namedComponent struct {
+       Component
+       name string
+}
+
+func (c namedComponent) String() string { return c.name }
+
+type uint128 struct {
+       name   string
+       hi, lo GPVirtual
+}
+
+func (c uint128) String() string { return c.name }
+
+func feSquare() {
+       TEXT("feSquare", NOSPLIT, "func(out, a *Element)")
+       Doc("feSquare sets out = a * a. It works like feSquareGeneric.")
+       Pragma("noescape")
+
+       a := Dereference(Param("a"))
+       l0 := namedComponent{a.Field("l0"), "l0"}
+       l1 := namedComponent{a.Field("l1"), "l1"}
+       l2 := namedComponent{a.Field("l2"), "l2"}
+       l3 := namedComponent{a.Field("l3"), "l3"}
+       l4 := namedComponent{a.Field("l4"), "l4"}
+
+       // r0 = l0×l0 + 19×2×(l1×l4 + l2×l3)
+       r0 := uint128{"r0", GP64(), GP64()}
+       mul64(r0, 1, l0, l0)
+       addMul64(r0, 38, l1, l4)
+       addMul64(r0, 38, l2, l3)
+
+       // r1 = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
+       r1 := uint128{"r1", GP64(), GP64()}
+       mul64(r1, 2, l0, l1)
+       addMul64(r1, 38, l2, l4)
+       addMul64(r1, 19, l3, l3)
+
+       // r2 = = 2×l0×l2 + l1×l1 + 19×2×l3×l4
+       r2 := uint128{"r2", GP64(), GP64()}
+       mul64(r2, 2, l0, l2)
+       addMul64(r2, 1, l1, l1)
+       addMul64(r2, 38, l3, l4)
+
+       // r3 = = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
+       r3 := uint128{"r3", GP64(), GP64()}
+       mul64(r3, 2, l0, l3)
+       addMul64(r3, 2, l1, l2)
+       addMul64(r3, 19, l4, l4)
+
+       // r4 = = 2×l0×l4 + 2×l1×l3 + l2×l2
+       r4 := uint128{"r4", GP64(), GP64()}
+       mul64(r4, 2, l0, l4)
+       addMul64(r4, 2, l1, l3)
+       addMul64(r4, 1, l2, l2)
+
+       Comment("First reduction chain")
+       maskLow51Bits := GP64()
+       MOVQ(Imm((1<<51)-1), maskLow51Bits)
+       c0, r0lo := shiftRightBy51(&r0)
+       c1, r1lo := shiftRightBy51(&r1)
+       c2, r2lo := shiftRightBy51(&r2)
+       c3, r3lo := shiftRightBy51(&r3)
+       c4, r4lo := shiftRightBy51(&r4)
+       maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+       maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+       maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+       maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+       maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+       Comment("Second reduction chain (carryPropagate)")
+       // c0 = r0 >> 51
+       MOVQ(r0lo, c0)
+       SHRQ(Imm(51), c0)
+       // c1 = r1 >> 51
+       MOVQ(r1lo, c1)
+       SHRQ(Imm(51), c1)
+       // c2 = r2 >> 51
+       MOVQ(r2lo, c2)
+       SHRQ(Imm(51), c2)
+       // c3 = r3 >> 51
+       MOVQ(r3lo, c3)
+       SHRQ(Imm(51), c3)
+       // c4 = r4 >> 51
+       MOVQ(r4lo, c4)
+       SHRQ(Imm(51), c4)
+       maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+       maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+       maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+       maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+       maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+       Comment("Store output")
+       out := Dereference(Param("out"))
+       Store(r0lo, out.Field("l0"))
+       Store(r1lo, out.Field("l1"))
+       Store(r2lo, out.Field("l2"))
+       Store(r3lo, out.Field("l3"))
+       Store(r4lo, out.Field("l4"))
+
+       RET()
+}
+
+func feMul() {
+       TEXT("feMul", NOSPLIT, "func(out, a, b *Element)")
+       Doc("feMul sets out = a * b. It works like feMulGeneric.")
+       Pragma("noescape")
+
+       a := Dereference(Param("a"))
+       a0 := namedComponent{a.Field("l0"), "a0"}
+       a1 := namedComponent{a.Field("l1"), "a1"}
+       a2 := namedComponent{a.Field("l2"), "a2"}
+       a3 := namedComponent{a.Field("l3"), "a3"}
+       a4 := namedComponent{a.Field("l4"), "a4"}
+
+       b := Dereference(Param("b"))
+       b0 := namedComponent{b.Field("l0"), "b0"}
+       b1 := namedComponent{b.Field("l1"), "b1"}
+       b2 := namedComponent{b.Field("l2"), "b2"}
+       b3 := namedComponent{b.Field("l3"), "b3"}
+       b4 := namedComponent{b.Field("l4"), "b4"}
+
+       // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+       r0 := uint128{"r0", GP64(), GP64()}
+       mul64(r0, 1, a0, b0)
+       addMul64(r0, 19, a1, b4)
+       addMul64(r0, 19, a2, b3)
+       addMul64(r0, 19, a3, b2)
+       addMul64(r0, 19, a4, b1)
+
+       // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
+       r1 := uint128{"r1", GP64(), GP64()}
+       mul64(r1, 1, a0, b1)
+       addMul64(r1, 1, a1, b0)
+       addMul64(r1, 19, a2, b4)
+       addMul64(r1, 19, a3, b3)
+       addMul64(r1, 19, a4, b2)
+
+       // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
+       r2 := uint128{"r2", GP64(), GP64()}
+       mul64(r2, 1, a0, b2)
+       addMul64(r2, 1, a1, b1)
+       addMul64(r2, 1, a2, b0)
+       addMul64(r2, 19, a3, b4)
+       addMul64(r2, 19, a4, b3)
+
+       // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
+       r3 := uint128{"r3", GP64(), GP64()}
+       mul64(r3, 1, a0, b3)
+       addMul64(r3, 1, a1, b2)
+       addMul64(r3, 1, a2, b1)
+       addMul64(r3, 1, a3, b0)
+       addMul64(r3, 19, a4, b4)
+
+       // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+       r4 := uint128{"r4", GP64(), GP64()}
+       mul64(r4, 1, a0, b4)
+       addMul64(r4, 1, a1, b3)
+       addMul64(r4, 1, a2, b2)
+       addMul64(r4, 1, a3, b1)
+       addMul64(r4, 1, a4, b0)
+
+       Comment("First reduction chain")
+       maskLow51Bits := GP64()
+       MOVQ(Imm((1<<51)-1), maskLow51Bits)
+       c0, r0lo := shiftRightBy51(&r0)
+       c1, r1lo := shiftRightBy51(&r1)
+       c2, r2lo := shiftRightBy51(&r2)
+       c3, r3lo := shiftRightBy51(&r3)
+       c4, r4lo := shiftRightBy51(&r4)
+       maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+       maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+       maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+       maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+       maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+       Comment("Second reduction chain (carryPropagate)")
+       // c0 = r0 >> 51
+       MOVQ(r0lo, c0)
+       SHRQ(Imm(51), c0)
+       // c1 = r1 >> 51
+       MOVQ(r1lo, c1)
+       SHRQ(Imm(51), c1)
+       // c2 = r2 >> 51
+       MOVQ(r2lo, c2)
+       SHRQ(Imm(51), c2)
+       // c3 = r3 >> 51
+       MOVQ(r3lo, c3)
+       SHRQ(Imm(51), c3)
+       // c4 = r4 >> 51
+       MOVQ(r4lo, c4)
+       SHRQ(Imm(51), c4)
+       maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+       maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+       maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+       maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+       maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+       Comment("Store output")
+       out := Dereference(Param("out"))
+       Store(r0lo, out.Field("l0"))
+       Store(r1lo, out.Field("l1"))
+       Store(r2lo, out.Field("l2"))
+       Store(r3lo, out.Field("l3"))
+       Store(r4lo, out.Field("l4"))
+
+       RET()
+}
+
+// mul64 sets r to i * aX * bX.
+func mul64(r uint128, i int, aX, bX namedComponent) {
+       switch i {
+       case 1:
+               Comment(fmt.Sprintf("%s = %s×%s", r, aX, bX))
+               Load(aX, RAX)
+       case 2:
+               Comment(fmt.Sprintf("%s = 2×%s×%s", r, aX, bX))
+               Load(aX, RAX)
+               SHLQ(Imm(1), RAX)
+       default:
+               panic("unsupported i value")
+       }
+       MULQ(mustAddr(bX)) // RDX, RAX = RAX * bX
+       MOVQ(RAX, r.lo)
+       MOVQ(RDX, r.hi)
+}
+
+// addMul64 sets r to r + i * aX * bX.
+func addMul64(r uint128, i uint64, aX, bX namedComponent) {
+       switch i {
+       case 1:
+               Comment(fmt.Sprintf("%s += %s×%s", r, aX, bX))
+               Load(aX, RAX)
+       default:
+               Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
+               IMUL3Q(Imm(i), Load(aX, GP64()), RAX)
+       }
+       MULQ(mustAddr(bX)) // RDX, RAX = RAX * bX
+       ADDQ(RAX, r.lo)
+       ADCQ(RDX, r.hi)
+}
+
+// shiftRightBy51 returns r >> 51 and r.lo.
+//
+// After this function is called, the uint128 may not be used anymore.
+func shiftRightBy51(r *uint128) (out, lo GPVirtual) {
+       out = r.hi
+       lo = r.lo
+       SHLQ(Imm(64-51), r.lo, r.hi)
+       r.lo, r.hi = nil, nil // make sure the uint128 is unusable
+       return
+}
+
+// maskAndAdd sets r = r&mask + c*i.
+func maskAndAdd(r, mask, c GPVirtual, i uint64) {
+       ANDQ(mask, r)
+       if i != 1 {
+               IMUL3Q(Imm(i), c, c)
+       }
+       ADDQ(c, r)
+}
+
+func mustAddr(c Component) Op {
+       b, err := c.Resolve()
+       if err != nil {
+               panic(err)
+       }
+       return b.Addr
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/go.mod b/go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/go.mod
new file mode 100644 (file)
index 0000000..b79d9f0
--- /dev/null
@@ -0,0 +1,12 @@
+module go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/field/_asm
+
+go 1.19
+
+require github.com/mmcloughlin/avo v0.4.0
+
+require (
+       golang.org/x/mod v0.4.2 // indirect
+       golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 // indirect
+       golang.org/x/tools v0.1.7 // indirect
+       golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+)
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/go.sum b/go/cm/sign/ed25519-blake2b/edwards25519/field/_asm/go.sum
new file mode 100644 (file)
index 0000000..40c7a0b
--- /dev/null
@@ -0,0 +1,32 @@
+github.com/mmcloughlin/avo v0.4.0 h1:jeHDRktVD+578ULxWpQHkilor6pkdLF7u7EiTzDbfcU=
+github.com/mmcloughlin/avo v0.4.0/go.mod h1:RW9BfYA3TgO9uCdNrKU2h6J8cPD8ZLznvfgHAeszb1s=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 h1:giLT+HuUP/gXYrG2Plg9WTjj4qhfgaW424ZIFog3rlk=
+golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe.go
new file mode 100644 (file)
index 0000000..821775c
--- /dev/null
@@ -0,0 +1,423 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package field implements fast arithmetic modulo 2^255-19.
+package field
+
+import (
+       "errors"
+       "math/bits"
+
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/byteorder"
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/subtle"
+)
+
+// Element represents an element of the field GF(2^255-19). Note that this
+// is not a cryptographically secure group, and should only be used to interact
+// with edwards25519.Point coordinates.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Element struct {
+       // An element t represents the integer
+       //     t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
+       //
+       // Between operations, all limbs are expected to be lower than 2^52.
+       l0 uint64
+       l1 uint64
+       l2 uint64
+       l3 uint64
+       l4 uint64
+}
+
+const maskLow51Bits uint64 = (1 << 51) - 1
+
+var feZero = &Element{0, 0, 0, 0, 0}
+
+// Zero sets v = 0, and returns v.
+func (v *Element) Zero() *Element {
+       *v = *feZero
+       return v
+}
+
+var feOne = &Element{1, 0, 0, 0, 0}
+
+// One sets v = 1, and returns v.
+func (v *Element) One() *Element {
+       *v = *feOne
+       return v
+}
+
+// reduce reduces v modulo 2^255 - 19 and returns it.
+func (v *Element) reduce() *Element {
+       v.carryPropagate()
+
+       // After the light reduction we now have a field element representation
+       // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
+
+       // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
+       // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
+       c := (v.l0 + 19) >> 51
+       c = (v.l1 + c) >> 51
+       c = (v.l2 + c) >> 51
+       c = (v.l3 + c) >> 51
+       c = (v.l4 + c) >> 51
+
+       // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
+       // effectively applying the reduction identity to the carry.
+       v.l0 += 19 * c
+
+       v.l1 += v.l0 >> 51
+       v.l0 = v.l0 & maskLow51Bits
+       v.l2 += v.l1 >> 51
+       v.l1 = v.l1 & maskLow51Bits
+       v.l3 += v.l2 >> 51
+       v.l2 = v.l2 & maskLow51Bits
+       v.l4 += v.l3 >> 51
+       v.l3 = v.l3 & maskLow51Bits
+       // no additional carry
+       v.l4 = v.l4 & maskLow51Bits
+
+       return v
+}
+
+// Add sets v = a + b, and returns v.
+func (v *Element) Add(a, b *Element) *Element {
+       v.l0 = a.l0 + b.l0
+       v.l1 = a.l1 + b.l1
+       v.l2 = a.l2 + b.l2
+       v.l3 = a.l3 + b.l3
+       v.l4 = a.l4 + b.l4
+       // Using the generic implementation here is actually faster than the
+       // assembly. Probably because the body of this function is so simple that
+       // the compiler can figure out better optimizations by inlining the carry
+       // propagation.
+       return v.carryPropagateGeneric()
+}
+
+// Subtract sets v = a - b, and returns v.
+func (v *Element) Subtract(a, b *Element) *Element {
+       // We first add 2 * p, to guarantee the subtraction won't underflow, and
+       // then subtract b (which can be up to 2^255 + 2^13 * 19).
+       v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
+       v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
+       v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
+       v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
+       v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
+       return v.carryPropagate()
+}
+
+// Negate sets v = -a, and returns v.
+func (v *Element) Negate(a *Element) *Element {
+       return v.Subtract(feZero, a)
+}
+
+// Invert sets v = 1/z mod p, and returns v.
+//
+// If z == 0, Invert returns v = 0.
+func (v *Element) Invert(z *Element) *Element {
+       // Inversion is implemented as exponentiation with exponent p − 2. It uses the
+       // same sequence of 255 squarings and 11 multiplications as [Curve25519].
+       var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
+
+       z2.Square(z)             // 2
+       t.Square(&z2)            // 4
+       t.Square(&t)             // 8
+       z9.Multiply(&t, z)       // 9
+       z11.Multiply(&z9, &z2)   // 11
+       t.Square(&z11)           // 22
+       z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
+
+       t.Square(&z2_5_0) // 2^6 - 2^1
+       for i := 0; i < 4; i++ {
+               t.Square(&t) // 2^10 - 2^5
+       }
+       z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
+
+       t.Square(&z2_10_0) // 2^11 - 2^1
+       for i := 0; i < 9; i++ {
+               t.Square(&t) // 2^20 - 2^10
+       }
+       z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
+
+       t.Square(&z2_20_0) // 2^21 - 2^1
+       for i := 0; i < 19; i++ {
+               t.Square(&t) // 2^40 - 2^20
+       }
+       t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
+
+       t.Square(&t) // 2^41 - 2^1
+       for i := 0; i < 9; i++ {
+               t.Square(&t) // 2^50 - 2^10
+       }
+       z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
+
+       t.Square(&z2_50_0) // 2^51 - 2^1
+       for i := 0; i < 49; i++ {
+               t.Square(&t) // 2^100 - 2^50
+       }
+       z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
+
+       t.Square(&z2_100_0) // 2^101 - 2^1
+       for i := 0; i < 99; i++ {
+               t.Square(&t) // 2^200 - 2^100
+       }
+       t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
+
+       t.Square(&t) // 2^201 - 2^1
+       for i := 0; i < 49; i++ {
+               t.Square(&t) // 2^250 - 2^50
+       }
+       t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
+
+       t.Square(&t) // 2^251 - 2^1
+       t.Square(&t) // 2^252 - 2^2
+       t.Square(&t) // 2^253 - 2^3
+       t.Square(&t) // 2^254 - 2^4
+       t.Square(&t) // 2^255 - 2^5
+
+       return v.Multiply(&t, &z11) // 2^255 - 21
+}
+
+// Set sets v = a, and returns v.
+func (v *Element) Set(a *Element) *Element {
+       *v = *a
+       return v
+}
+
+// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is
+// not of the right length, SetBytes returns nil and an error, and the
+// receiver is unchanged.
+//
+// Consistent with RFC 7748, the most significant bit (the high bit of the
+// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
+// are accepted. Note that this is laxer than specified by RFC 8032, but
+// consistent with most Ed25519 implementations.
+func (v *Element) SetBytes(x []byte) (*Element, error) {
+       if len(x) != 32 {
+               return nil, errors.New("edwards25519: invalid field element input size")
+       }
+
+       // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
+       v.l0 = byteorder.LEUint64(x[0:8])
+       v.l0 &= maskLow51Bits
+       // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
+       v.l1 = byteorder.LEUint64(x[6:14]) >> 3
+       v.l1 &= maskLow51Bits
+       // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
+       v.l2 = byteorder.LEUint64(x[12:20]) >> 6
+       v.l2 &= maskLow51Bits
+       // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
+       v.l3 = byteorder.LEUint64(x[19:27]) >> 1
+       v.l3 &= maskLow51Bits
+       // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51).
+       // Note: not bytes 25:33, shift 4, to avoid overread.
+       v.l4 = byteorder.LEUint64(x[24:32]) >> 12
+       v.l4 &= maskLow51Bits
+
+       return v, nil
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of v.
+func (v *Element) Bytes() []byte {
+       // This function is outlined to make the allocations inline in the caller
+       // rather than happen on the heap.
+       var out [32]byte
+       return v.bytes(&out)
+}
+
+func (v *Element) bytes(out *[32]byte) []byte {
+       t := *v
+       t.reduce()
+
+       var buf [8]byte
+       for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
+               bitsOffset := i * 51
+               byteorder.LEPutUint64(buf[:], l<<uint(bitsOffset%8))
+               for i, bb := range buf {
+                       off := bitsOffset/8 + i
+                       if off >= len(out) {
+                               break
+                       }
+                       out[off] |= bb
+               }
+       }
+
+       return out[:]
+}
+
+// Equal returns 1 if v and u are equal, and 0 otherwise.
+func (v *Element) Equal(u *Element) int {
+       sa, sv := u.Bytes(), v.Bytes()
+       return subtle.ConstantTimeCompare(sa, sv)
+}
+
+// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
+func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *Element) Select(a, b *Element, cond int) *Element {
+       m := mask64Bits(cond)
+       v.l0 = (m & a.l0) | (^m & b.l0)
+       v.l1 = (m & a.l1) | (^m & b.l1)
+       v.l2 = (m & a.l2) | (^m & b.l2)
+       v.l3 = (m & a.l3) | (^m & b.l3)
+       v.l4 = (m & a.l4) | (^m & b.l4)
+       return v
+}
+
+// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
+func (v *Element) Swap(u *Element, cond int) {
+       m := mask64Bits(cond)
+       t := m & (v.l0 ^ u.l0)
+       v.l0 ^= t
+       u.l0 ^= t
+       t = m & (v.l1 ^ u.l1)
+       v.l1 ^= t
+       u.l1 ^= t
+       t = m & (v.l2 ^ u.l2)
+       v.l2 ^= t
+       u.l2 ^= t
+       t = m & (v.l3 ^ u.l3)
+       v.l3 ^= t
+       u.l3 ^= t
+       t = m & (v.l4 ^ u.l4)
+       v.l4 ^= t
+       u.l4 ^= t
+}
+
+// IsNegative returns 1 if v is negative, and 0 otherwise.
+func (v *Element) IsNegative() int {
+       return int(v.Bytes()[0] & 1)
+}
+
+// Absolute sets v to |u|, and returns v.
+func (v *Element) Absolute(u *Element) *Element {
+       return v.Select(new(Element).Negate(u), u, u.IsNegative())
+}
+
+// Multiply sets v = x * y, and returns v.
+func (v *Element) Multiply(x, y *Element) *Element {
+       feMul(v, x, y)
+       return v
+}
+
+// Square sets v = x * x, and returns v.
+func (v *Element) Square(x *Element) *Element {
+       feSquare(v, x)
+       return v
+}
+
+// Mult32 sets v = x * y, and returns v.
+func (v *Element) Mult32(x *Element, y uint32) *Element {
+       x0lo, x0hi := mul51(x.l0, y)
+       x1lo, x1hi := mul51(x.l1, y)
+       x2lo, x2hi := mul51(x.l2, y)
+       x3lo, x3hi := mul51(x.l3, y)
+       x4lo, x4hi := mul51(x.l4, y)
+       v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
+       v.l1 = x1lo + x0hi
+       v.l2 = x2lo + x1hi
+       v.l3 = x3lo + x2hi
+       v.l4 = x4lo + x3hi
+       // The hi portions are going to be only 32 bits, plus any previous excess,
+       // so we can skip the carry propagation.
+       return v
+}
+
+// mul51 returns lo + hi * 2⁵¹ = a * b.
+func mul51(a uint64, b uint32) (lo, hi uint64) {
+       mh, ml := bits.Mul64(a, uint64(b))
+       lo = ml & maskLow51Bits
+       hi = (mh << 13) | (ml >> 51)
+       return
+}
+
+// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
+func (v *Element) Pow22523(x *Element) *Element {
+       var t0, t1, t2 Element
+
+       t0.Square(x)             // x^2
+       t1.Square(&t0)           // x^4
+       t1.Square(&t1)           // x^8
+       t1.Multiply(x, &t1)      // x^9
+       t0.Multiply(&t0, &t1)    // x^11
+       t0.Square(&t0)           // x^22
+       t0.Multiply(&t1, &t0)    // x^31
+       t1.Square(&t0)           // x^62
+       for i := 1; i < 5; i++ { // x^992
+               t1.Square(&t1)
+       }
+       t0.Multiply(&t1, &t0)     // x^1023 -> 1023 = 2^10 - 1
+       t1.Square(&t0)            // 2^11 - 2
+       for i := 1; i < 10; i++ { // 2^20 - 2^10
+               t1.Square(&t1)
+       }
+       t1.Multiply(&t1, &t0)     // 2^20 - 1
+       t2.Square(&t1)            // 2^21 - 2
+       for i := 1; i < 20; i++ { // 2^40 - 2^20
+               t2.Square(&t2)
+       }
+       t1.Multiply(&t2, &t1)     // 2^40 - 1
+       t1.Square(&t1)            // 2^41 - 2
+       for i := 1; i < 10; i++ { // 2^50 - 2^10
+               t1.Square(&t1)
+       }
+       t0.Multiply(&t1, &t0)     // 2^50 - 1
+       t1.Square(&t0)            // 2^51 - 2
+       for i := 1; i < 50; i++ { // 2^100 - 2^50
+               t1.Square(&t1)
+       }
+       t1.Multiply(&t1, &t0)      // 2^100 - 1
+       t2.Square(&t1)             // 2^101 - 2
+       for i := 1; i < 100; i++ { // 2^200 - 2^100
+               t2.Square(&t2)
+       }
+       t1.Multiply(&t2, &t1)     // 2^200 - 1
+       t1.Square(&t1)            // 2^201 - 2
+       for i := 1; i < 50; i++ { // 2^250 - 2^50
+               t1.Square(&t1)
+       }
+       t0.Multiply(&t1, &t0)     // 2^250 - 1
+       t0.Square(&t0)            // 2^251 - 2
+       t0.Square(&t0)            // 2^252 - 4
+       return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
+}
+
+// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
+var sqrtM1 = &Element{
+       1718705420411056, 234908883556509,
+       2233514472574048, 2117202627021982, 765476049583133,
+}
+
+// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
+//
+// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
+// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
+// and returns r and 0.
+func (r *Element) SqrtRatio(u, v *Element) (R *Element, wasSquare int) {
+       t0 := new(Element)
+
+       // r = (u * v3) * (u * v7)^((p-5)/8)
+       v2 := new(Element).Square(v)
+       uv3 := new(Element).Multiply(u, t0.Multiply(v2, v))
+       uv7 := new(Element).Multiply(uv3, t0.Square(v2))
+       rr := new(Element).Multiply(uv3, t0.Pow22523(uv7))
+
+       check := new(Element).Multiply(v, t0.Square(rr)) // check = v * r^2
+
+       uNeg := new(Element).Negate(u)
+       correctSignSqrt := check.Equal(u)
+       flippedSignSqrt := check.Equal(uNeg)
+       flippedSignSqrtI := check.Equal(t0.Multiply(uNeg, sqrtM1))
+
+       rPrime := new(Element).Multiply(rr, sqrtM1) // r_prime = SQRT_M1 * r
+       // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
+       rr.Select(rPrime, rr, flippedSignSqrt|flippedSignSqrtI)
+
+       r.Absolute(rr) // Choose the nonnegative square root.
+       return r, correctSignSqrt | flippedSignSqrt
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64.go
new file mode 100644 (file)
index 0000000..d45675a
--- /dev/null
@@ -0,0 +1,15 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build !purego
+
+package field
+
+// feMul sets out = a * b. It works like feMulGeneric.
+//
+//go:noescape
+func feMul(out *Element, a *Element, b *Element)
+
+// feSquare sets out = a * a. It works like feSquareGeneric.
+//
+//go:noescape
+func feSquare(out *Element, a *Element)
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64.s b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64.s
new file mode 100644 (file)
index 0000000..eaf2751
--- /dev/null
@@ -0,0 +1,378 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func feMul(out *Element, a *Element, b *Element)
+TEXT ·feMul(SB), NOSPLIT, $0-24
+       MOVQ a+8(FP), CX
+       MOVQ b+16(FP), BX
+
+       // r0 = a0×b0
+       MOVQ (CX), AX
+       MULQ (BX)
+       MOVQ AX, DI
+       MOVQ DX, SI
+
+       // r0 += 19×a1×b4
+       MOVQ   8(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r0 += 19×a2×b3
+       MOVQ   16(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r0 += 19×a3×b2
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   16(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r0 += 19×a4×b1
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   8(BX)
+       ADDQ   AX, DI
+       ADCQ   DX, SI
+
+       // r1 = a0×b1
+       MOVQ (CX), AX
+       MULQ 8(BX)
+       MOVQ AX, R9
+       MOVQ DX, R8
+
+       // r1 += a1×b0
+       MOVQ 8(CX), AX
+       MULQ (BX)
+       ADDQ AX, R9
+       ADCQ DX, R8
+
+       // r1 += 19×a2×b4
+       MOVQ   16(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, R9
+       ADCQ   DX, R8
+
+       // r1 += 19×a3×b3
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(BX)
+       ADDQ   AX, R9
+       ADCQ   DX, R8
+
+       // r1 += 19×a4×b2
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   16(BX)
+       ADDQ   AX, R9
+       ADCQ   DX, R8
+
+       // r2 = a0×b2
+       MOVQ (CX), AX
+       MULQ 16(BX)
+       MOVQ AX, R11
+       MOVQ DX, R10
+
+       // r2 += a1×b1
+       MOVQ 8(CX), AX
+       MULQ 8(BX)
+       ADDQ AX, R11
+       ADCQ DX, R10
+
+       // r2 += a2×b0
+       MOVQ 16(CX), AX
+       MULQ (BX)
+       ADDQ AX, R11
+       ADCQ DX, R10
+
+       // r2 += 19×a3×b4
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, R11
+       ADCQ   DX, R10
+
+       // r2 += 19×a4×b3
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(BX)
+       ADDQ   AX, R11
+       ADCQ   DX, R10
+
+       // r3 = a0×b3
+       MOVQ (CX), AX
+       MULQ 24(BX)
+       MOVQ AX, R13
+       MOVQ DX, R12
+
+       // r3 += a1×b2
+       MOVQ 8(CX), AX
+       MULQ 16(BX)
+       ADDQ AX, R13
+       ADCQ DX, R12
+
+       // r3 += a2×b1
+       MOVQ 16(CX), AX
+       MULQ 8(BX)
+       ADDQ AX, R13
+       ADCQ DX, R12
+
+       // r3 += a3×b0
+       MOVQ 24(CX), AX
+       MULQ (BX)
+       ADDQ AX, R13
+       ADCQ DX, R12
+
+       // r3 += 19×a4×b4
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(BX)
+       ADDQ   AX, R13
+       ADCQ   DX, R12
+
+       // r4 = a0×b4
+       MOVQ (CX), AX
+       MULQ 32(BX)
+       MOVQ AX, R15
+       MOVQ DX, R14
+
+       // r4 += a1×b3
+       MOVQ 8(CX), AX
+       MULQ 24(BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // r4 += a2×b2
+       MOVQ 16(CX), AX
+       MULQ 16(BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // r4 += a3×b1
+       MOVQ 24(CX), AX
+       MULQ 8(BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // r4 += a4×b0
+       MOVQ 32(CX), AX
+       MULQ (BX)
+       ADDQ AX, R15
+       ADCQ DX, R14
+
+       // First reduction chain
+       MOVQ   $0x0007ffffffffffff, AX
+       SHLQ   $0x0d, DI, SI
+       SHLQ   $0x0d, R9, R8
+       SHLQ   $0x0d, R11, R10
+       SHLQ   $0x0d, R13, R12
+       SHLQ   $0x0d, R15, R14
+       ANDQ   AX, DI
+       IMUL3Q $0x13, R14, R14
+       ADDQ   R14, DI
+       ANDQ   AX, R9
+       ADDQ   SI, R9
+       ANDQ   AX, R11
+       ADDQ   R8, R11
+       ANDQ   AX, R13
+       ADDQ   R10, R13
+       ANDQ   AX, R15
+       ADDQ   R12, R15
+
+       // Second reduction chain (carryPropagate)
+       MOVQ   DI, SI
+       SHRQ   $0x33, SI
+       MOVQ   R9, R8
+       SHRQ   $0x33, R8
+       MOVQ   R11, R10
+       SHRQ   $0x33, R10
+       MOVQ   R13, R12
+       SHRQ   $0x33, R12
+       MOVQ   R15, R14
+       SHRQ   $0x33, R14
+       ANDQ   AX, DI
+       IMUL3Q $0x13, R14, R14
+       ADDQ   R14, DI
+       ANDQ   AX, R9
+       ADDQ   SI, R9
+       ANDQ   AX, R11
+       ADDQ   R8, R11
+       ANDQ   AX, R13
+       ADDQ   R10, R13
+       ANDQ   AX, R15
+       ADDQ   R12, R15
+
+       // Store output
+       MOVQ out+0(FP), AX
+       MOVQ DI, (AX)
+       MOVQ R9, 8(AX)
+       MOVQ R11, 16(AX)
+       MOVQ R13, 24(AX)
+       MOVQ R15, 32(AX)
+       RET
+
+// func feSquare(out *Element, a *Element)
+TEXT ·feSquare(SB), NOSPLIT, $0-16
+       MOVQ a+8(FP), CX
+
+       // r0 = l0×l0
+       MOVQ (CX), AX
+       MULQ (CX)
+       MOVQ AX, SI
+       MOVQ DX, BX
+
+       // r0 += 38×l1×l4
+       MOVQ   8(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, SI
+       ADCQ   DX, BX
+
+       // r0 += 38×l2×l3
+       MOVQ   16(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   24(CX)
+       ADDQ   AX, SI
+       ADCQ   DX, BX
+
+       // r1 = 2×l0×l1
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 8(CX)
+       MOVQ AX, R8
+       MOVQ DX, DI
+
+       // r1 += 38×l2×l4
+       MOVQ   16(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, R8
+       ADCQ   DX, DI
+
+       // r1 += 19×l3×l3
+       MOVQ   24(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   24(CX)
+       ADDQ   AX, R8
+       ADCQ   DX, DI
+
+       // r2 = 2×l0×l2
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 16(CX)
+       MOVQ AX, R10
+       MOVQ DX, R9
+
+       // r2 += l1×l1
+       MOVQ 8(CX), AX
+       MULQ 8(CX)
+       ADDQ AX, R10
+       ADCQ DX, R9
+
+       // r2 += 38×l3×l4
+       MOVQ   24(CX), AX
+       IMUL3Q $0x26, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, R10
+       ADCQ   DX, R9
+
+       // r3 = 2×l0×l3
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 24(CX)
+       MOVQ AX, R12
+       MOVQ DX, R11
+
+       // r3 += 2×l1×l2
+       MOVQ   8(CX), AX
+       IMUL3Q $0x02, AX, AX
+       MULQ   16(CX)
+       ADDQ   AX, R12
+       ADCQ   DX, R11
+
+       // r3 += 19×l4×l4
+       MOVQ   32(CX), AX
+       IMUL3Q $0x13, AX, AX
+       MULQ   32(CX)
+       ADDQ   AX, R12
+       ADCQ   DX, R11
+
+       // r4 = 2×l0×l4
+       MOVQ (CX), AX
+       SHLQ $0x01, AX
+       MULQ 32(CX)
+       MOVQ AX, R14
+       MOVQ DX, R13
+
+       // r4 += 2×l1×l3
+       MOVQ   8(CX), AX
+       IMUL3Q $0x02, AX, AX
+       MULQ   24(CX)
+       ADDQ   AX, R14
+       ADCQ   DX, R13
+
+       // r4 += l2×l2
+       MOVQ 16(CX), AX
+       MULQ 16(CX)
+       ADDQ AX, R14
+       ADCQ DX, R13
+
+       // First reduction chain
+       MOVQ   $0x0007ffffffffffff, AX
+       SHLQ   $0x0d, SI, BX
+       SHLQ   $0x0d, R8, DI
+       SHLQ   $0x0d, R10, R9
+       SHLQ   $0x0d, R12, R11
+       SHLQ   $0x0d, R14, R13
+       ANDQ   AX, SI
+       IMUL3Q $0x13, R13, R13
+       ADDQ   R13, SI
+       ANDQ   AX, R8
+       ADDQ   BX, R8
+       ANDQ   AX, R10
+       ADDQ   DI, R10
+       ANDQ   AX, R12
+       ADDQ   R9, R12
+       ANDQ   AX, R14
+       ADDQ   R11, R14
+
+       // Second reduction chain (carryPropagate)
+       MOVQ   SI, BX
+       SHRQ   $0x33, BX
+       MOVQ   R8, DI
+       SHRQ   $0x33, DI
+       MOVQ   R10, R9
+       SHRQ   $0x33, R9
+       MOVQ   R12, R11
+       SHRQ   $0x33, R11
+       MOVQ   R14, R13
+       SHRQ   $0x33, R13
+       ANDQ   AX, SI
+       IMUL3Q $0x13, R13, R13
+       ADDQ   R13, SI
+       ANDQ   AX, R8
+       ADDQ   BX, R8
+       ANDQ   AX, R10
+       ADDQ   DI, R10
+       ANDQ   AX, R12
+       ADDQ   R9, R12
+       ANDQ   AX, R14
+       ADDQ   R11, R14
+
+       // Store output
+       MOVQ out+0(FP), AX
+       MOVQ SI, (AX)
+       MOVQ R8, 8(AX)
+       MOVQ R10, 16(AX)
+       MOVQ R12, 24(AX)
+       MOVQ R14, 32(AX)
+       RET
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64_noasm.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_amd64_noasm.go
new file mode 100644 (file)
index 0000000..d12b017
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 || purego
+
+package field
+
+func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
+
+func feSquare(v, x *Element) { feSquareGeneric(v, x) }
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64.go
new file mode 100644 (file)
index 0000000..5a1b958
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright (c) 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+package field
+
+//go:noescape
+func carryPropagate(v *Element)
+
+func (v *Element) carryPropagate() *Element {
+       carryPropagate(v)
+       return v
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64.s b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64.s
new file mode 100644 (file)
index 0000000..1b0528c
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// carryPropagate works exactly like carryPropagateGeneric and uses the
+// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
+// avoids loading R0-R4 twice and uses LDP and STP.
+//
+// See https://golang.org/issues/43145 for the main compiler issue.
+//
+// func carryPropagate(v *Element)
+TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
+       MOVD v+0(FP), R20
+
+       LDP 0(R20), (R0, R1)
+       LDP 16(R20), (R2, R3)
+       MOVD 32(R20), R4
+
+       AND $0x7ffffffffffff, R0, R10
+       AND $0x7ffffffffffff, R1, R11
+       AND $0x7ffffffffffff, R2, R12
+       AND $0x7ffffffffffff, R3, R13
+       AND $0x7ffffffffffff, R4, R14
+
+       ADD R0>>51, R11, R11
+       ADD R1>>51, R12, R12
+       ADD R2>>51, R13, R13
+       ADD R3>>51, R14, R14
+       // R4>>51 * 19 + R10 -> R10
+       LSR $51, R4, R21
+       MOVD $19, R22
+       MADD R22, R10, R21, R10
+
+       STP (R10, R11), 0(R20)
+       STP (R12, R13), 16(R20)
+       MOVD R14, 32(R20)
+
+       RET
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64_noasm.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_arm64_noasm.go
new file mode 100644 (file)
index 0000000..a3c2e55
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !arm64 || purego
+
+package field
+
+func (v *Element) carryPropagate() *Element {
+       return v.carryPropagateGeneric()
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_generic.go b/go/cm/sign/ed25519-blake2b/edwards25519/field/fe_generic.go
new file mode 100644 (file)
index 0000000..4272bf7
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import "math/bits"
+
+// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
+// bits.Mul64 and bits.Add64 intrinsics.
+type uint128 struct {
+       lo, hi uint64
+}
+
+// mul64 returns a * b.
+func mul64(a, b uint64) uint128 {
+       hi, lo := bits.Mul64(a, b)
+       return uint128{lo, hi}
+}
+
+// addMul64 returns v + a * b.
+func addMul64(v uint128, a, b uint64) uint128 {
+       hi, lo := bits.Mul64(a, b)
+       lo, c := bits.Add64(lo, v.lo, 0)
+       hi, _ = bits.Add64(hi, v.hi, c)
+       return uint128{lo, hi}
+}
+
+// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
+func shiftRightBy51(a uint128) uint64 {
+       return (a.hi << (64 - 51)) | (a.lo >> 51)
+}
+
+func feMulGeneric(v, a, b *Element) {
+       a0 := a.l0
+       a1 := a.l1
+       a2 := a.l2
+       a3 := a.l3
+       a4 := a.l4
+
+       b0 := b.l0
+       b1 := b.l1
+       b2 := b.l2
+       b3 := b.l3
+       b4 := b.l4
+
+       // Limb multiplication works like pen-and-paper columnar multiplication, but
+       // with 51-bit limbs instead of digits.
+       //
+       //                          a4   a3   a2   a1   a0  x
+       //                          b4   b3   b2   b1   b0  =
+       //                         ------------------------
+       //                        a4b0 a3b0 a2b0 a1b0 a0b0  +
+       //                   a4b1 a3b1 a2b1 a1b1 a0b1       +
+       //              a4b2 a3b2 a2b2 a1b2 a0b2            +
+       //         a4b3 a3b3 a2b3 a1b3 a0b3                 +
+       //    a4b4 a3b4 a2b4 a1b4 a0b4                      =
+       //   ----------------------------------------------
+       //      r8   r7   r6   r5   r4   r3   r2   r1   r0
+       //
+       // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
+       // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
+       // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
+       //
+       // Reduction can be carried out simultaneously to multiplication. For
+       // example, we do not compute r5: whenever the result of a multiplication
+       // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
+       //
+       //            a4b0    a3b0    a2b0    a1b0    a0b0  +
+       //            a3b1    a2b1    a1b1    a0b1 19×a4b1  +
+       //            a2b2    a1b2    a0b2 19×a4b2 19×a3b2  +
+       //            a1b3    a0b3 19×a4b3 19×a3b3 19×a2b3  +
+       //            a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4  =
+       //           --------------------------------------
+       //              r4      r3      r2      r1      r0
+       //
+       // Finally we add up the columns into wide, overlapping limbs.
+
+       a1_19 := a1 * 19
+       a2_19 := a2 * 19
+       a3_19 := a3 * 19
+       a4_19 := a4 * 19
+
+       // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+       r0 := mul64(a0, b0)
+       r0 = addMul64(r0, a1_19, b4)
+       r0 = addMul64(r0, a2_19, b3)
+       r0 = addMul64(r0, a3_19, b2)
+       r0 = addMul64(r0, a4_19, b1)
+
+       // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
+       r1 := mul64(a0, b1)
+       r1 = addMul64(r1, a1, b0)
+       r1 = addMul64(r1, a2_19, b4)
+       r1 = addMul64(r1, a3_19, b3)
+       r1 = addMul64(r1, a4_19, b2)
+
+       // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
+       r2 := mul64(a0, b2)
+       r2 = addMul64(r2, a1, b1)
+       r2 = addMul64(r2, a2, b0)
+       r2 = addMul64(r2, a3_19, b4)
+       r2 = addMul64(r2, a4_19, b3)
+
+       // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
+       r3 := mul64(a0, b3)
+       r3 = addMul64(r3, a1, b2)
+       r3 = addMul64(r3, a2, b1)
+       r3 = addMul64(r3, a3, b0)
+       r3 = addMul64(r3, a4_19, b4)
+
+       // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+       r4 := mul64(a0, b4)
+       r4 = addMul64(r4, a1, b3)
+       r4 = addMul64(r4, a2, b2)
+       r4 = addMul64(r4, a3, b1)
+       r4 = addMul64(r4, a4, b0)
+
+       // After the multiplication, we need to reduce (carry) the five coefficients
+       // to obtain a result with limbs that are at most slightly larger than 2⁵¹,
+       // to respect the Element invariant.
+       //
+       // Overall, the reduction works the same as carryPropagate, except with
+       // wider inputs: we take the carry for each coefficient by shifting it right
+       // by 51, and add it to the limb above it. The top carry is multiplied by 19
+       // according to the reduction identity and added to the lowest limb.
+       //
+       // The largest coefficient (r0) will be at most 111 bits, which guarantees
+       // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
+       //
+       //     r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+       //     r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
+       //     r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
+       //     r0 < 2⁷ × 2⁵² × 2⁵²
+       //     r0 < 2¹¹¹
+       //
+       // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
+       // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
+       // allows us to easily apply the reduction identity.
+       //
+       //     r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+       //     r4 < 5 × 2⁵² × 2⁵²
+       //     r4 < 2¹⁰⁷
+       //
+
+       c0 := shiftRightBy51(r0)
+       c1 := shiftRightBy51(r1)
+       c2 := shiftRightBy51(r2)
+       c3 := shiftRightBy51(r3)
+       c4 := shiftRightBy51(r4)
+
+       rr0 := r0.lo&maskLow51Bits + c4*19
+       rr1 := r1.lo&maskLow51Bits + c0
+       rr2 := r2.lo&maskLow51Bits + c1
+       rr3 := r3.lo&maskLow51Bits + c2
+       rr4 := r4.lo&maskLow51Bits + c3
+
+       // Now all coefficients fit into 64-bit registers but are still too large to
+       // be passed around as an Element. We therefore do one last carry chain,
+       // where the carries will be small enough to fit in the wiggle room above 2⁵¹.
+       *v = Element{rr0, rr1, rr2, rr3, rr4}
+       v.carryPropagate()
+}
+
+func feSquareGeneric(v, a *Element) {
+       l0 := a.l0
+       l1 := a.l1
+       l2 := a.l2
+       l3 := a.l3
+       l4 := a.l4
+
+       // Squaring works precisely like multiplication above, but thanks to its
+       // symmetry we get to group a few terms together.
+       //
+       //                          l4   l3   l2   l1   l0  x
+       //                          l4   l3   l2   l1   l0  =
+       //                         ------------------------
+       //                        l4l0 l3l0 l2l0 l1l0 l0l0  +
+       //                   l4l1 l3l1 l2l1 l1l1 l0l1       +
+       //              l4l2 l3l2 l2l2 l1l2 l0l2            +
+       //         l4l3 l3l3 l2l3 l1l3 l0l3                 +
+       //    l4l4 l3l4 l2l4 l1l4 l0l4                      =
+       //   ----------------------------------------------
+       //      r8   r7   r6   r5   r4   r3   r2   r1   r0
+       //
+       //            l4l0    l3l0    l2l0    l1l0    l0l0  +
+       //            l3l1    l2l1    l1l1    l0l1 19×l4l1  +
+       //            l2l2    l1l2    l0l2 19×l4l2 19×l3l2  +
+       //            l1l3    l0l3 19×l4l3 19×l3l3 19×l2l3  +
+       //            l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4  =
+       //           --------------------------------------
+       //              r4      r3      r2      r1      r0
+       //
+       // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
+       // only three Mul64 and four Add64, instead of five and eight.
+
+       l0_2 := l0 * 2
+       l1_2 := l1 * 2
+
+       l1_38 := l1 * 38
+       l2_38 := l2 * 38
+       l3_38 := l3 * 38
+
+       l3_19 := l3 * 19
+       l4_19 := l4 * 19
+
+       // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
+       r0 := mul64(l0, l0)
+       r0 = addMul64(r0, l1_38, l4)
+       r0 = addMul64(r0, l2_38, l3)
+
+       // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
+       r1 := mul64(l0_2, l1)
+       r1 = addMul64(r1, l2_38, l4)
+       r1 = addMul64(r1, l3_19, l3)
+
+       // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
+       r2 := mul64(l0_2, l2)
+       r2 = addMul64(r2, l1, l1)
+       r2 = addMul64(r2, l3_38, l4)
+
+       // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
+       r3 := mul64(l0_2, l3)
+       r3 = addMul64(r3, l1_2, l2)
+       r3 = addMul64(r3, l4_19, l4)
+
+       // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
+       r4 := mul64(l0_2, l4)
+       r4 = addMul64(r4, l1_2, l3)
+       r4 = addMul64(r4, l2, l2)
+
+       c0 := shiftRightBy51(r0)
+       c1 := shiftRightBy51(r1)
+       c2 := shiftRightBy51(r2)
+       c3 := shiftRightBy51(r3)
+       c4 := shiftRightBy51(r4)
+
+       rr0 := r0.lo&maskLow51Bits + c4*19
+       rr1 := r1.lo&maskLow51Bits + c0
+       rr2 := r2.lo&maskLow51Bits + c1
+       rr3 := r3.lo&maskLow51Bits + c2
+       rr4 := r4.lo&maskLow51Bits + c3
+
+       *v = Element{rr0, rr1, rr2, rr3, rr4}
+       v.carryPropagate()
+}
+
+// carryPropagateGeneric brings the limbs below 52 bits by applying the reduction
+// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry.
+func (v *Element) carryPropagateGeneric() *Element {
+       c0 := v.l0 >> 51
+       c1 := v.l1 >> 51
+       c2 := v.l2 >> 51
+       c3 := v.l3 >> 51
+       c4 := v.l4 >> 51
+
+       // c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and
+       // the final l0 will be at most 52 bits. Similarly for the rest.
+       v.l0 = v.l0&maskLow51Bits + c4*19
+       v.l1 = v.l1&maskLow51Bits + c0
+       v.l2 = v.l2&maskLow51Bits + c1
+       v.l3 = v.l3&maskLow51Bits + c2
+       v.l4 = v.l4&maskLow51Bits + c3
+
+       return v
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/scalar.go b/go/cm/sign/ed25519-blake2b/edwards25519/scalar.go
new file mode 100644 (file)
index 0000000..07b90aa
--- /dev/null
@@ -0,0 +1,349 @@
+// Copyright (c) 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+       "errors"
+
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/byteorder"
+)
+
+// A Scalar is an integer modulo
+//
+//     l = 2^252 + 27742317777372353535851937790883648493
+//
+// which is the prime order of the edwards25519 group.
+//
+// This type works similarly to math/big.Int, and all arguments and
+// receivers are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Scalar struct {
+       // s is the scalar in the Montgomery domain, in the format of the
+       // fiat-crypto implementation.
+       s fiatScalarMontgomeryDomainFieldElement
+}
+
+// The field implementation in scalar_fiat.go is generated by the fiat-crypto
+// project (https://github.com/mit-plv/fiat-crypto) at version v0.0.9 (23d2dbc)
+// from a formally verified model.
+//
+// fiat-crypto code comes under the following license.
+//
+//     Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved.
+//
+//     Redistribution and use in source and binary forms, with or without
+//     modification, are permitted provided that the following conditions are
+//     met:
+//
+//         1. Redistributions of source code must retain the above copyright
+//         notice, this list of conditions and the following disclaimer.
+//
+//     THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
+//     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+//     THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+//     PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
+//     Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+//     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+//     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//     NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+// NewScalar returns a new zero Scalar.
+func NewScalar() *Scalar {
+       return &Scalar{}
+}
+
+// MultiplyAdd sets s = x * y + z mod l, and returns s. It is equivalent to
+// using Multiply and then Add.
+func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar {
+       // Make a copy of z in case it aliases s.
+       zCopy := new(Scalar).Set(z)
+       return s.Multiply(x, y).Add(s, zCopy)
+}
+
+// Add sets s = x + y mod l, and returns s.
+func (s *Scalar) Add(x, y *Scalar) *Scalar {
+       // s = 1 * x + y mod l
+       fiatScalarAdd(&s.s, &x.s, &y.s)
+       return s
+}
+
+// Subtract sets s = x - y mod l, and returns s.
+func (s *Scalar) Subtract(x, y *Scalar) *Scalar {
+       // s = -1 * y + x mod l
+       fiatScalarSub(&s.s, &x.s, &y.s)
+       return s
+}
+
+// Negate sets s = -x mod l, and returns s.
+func (s *Scalar) Negate(x *Scalar) *Scalar {
+       // s = -1 * x + 0 mod l
+       fiatScalarOpp(&s.s, &x.s)
+       return s
+}
+
+// Multiply sets s = x * y mod l, and returns s.
+func (s *Scalar) Multiply(x, y *Scalar) *Scalar {
+       // s = x * y + 0 mod l
+       fiatScalarMul(&s.s, &x.s, &y.s)
+       return s
+}
+
+// Set sets s = x, and returns s.
+func (s *Scalar) Set(x *Scalar) *Scalar {
+       *s = *x
+       return s
+}
+
+// SetUniformBytes sets s = x mod l, where x is a 64-byte little-endian integer.
+// If x is not of the right length, SetUniformBytes returns nil and an error,
+// and the receiver is unchanged.
+//
+// SetUniformBytes can be used to set s to a uniformly distributed value given
+// 64 uniformly distributed random bytes.
+func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) {
+       if len(x) != 64 {
+               return nil, errors.New("edwards25519: invalid SetUniformBytes input length")
+       }
+
+       // We have a value x of 512 bits, but our fiatScalarFromBytes function
+       // expects an input lower than l, which is a little over 252 bits.
+       //
+       // Instead of writing a reduction function that operates on wider inputs, we
+       // can interpret x as the sum of three shorter values a, b, and c.
+       //
+       //    x = a + b * 2^168 + c * 2^336  mod l
+       //
+       // We then precompute 2^168 and 2^336 modulo l, and perform the reduction
+       // with two multiplications and two additions.
+
+       s.setShortBytes(x[:21])
+       t := new(Scalar).setShortBytes(x[21:42])
+       s.Add(s, t.Multiply(t, scalarTwo168))
+       t.setShortBytes(x[42:])
+       s.Add(s, t.Multiply(t, scalarTwo336))
+
+       return s, nil
+}
+
+// scalarTwo168 and scalarTwo336 are 2^168 and 2^336 modulo l, encoded as a
+// fiatScalarMontgomeryDomainFieldElement, which is a little-endian 4-limb value
+// in the 2^256 Montgomery domain.
+var scalarTwo168 = &Scalar{s: [4]uint64{
+       0x5b8ab432eac74798, 0x38afddd6de59d5d7,
+       0xa2c131b399411b7c, 0x6329a7ed9ce5a30,
+}}
+
+var scalarTwo336 = &Scalar{s: [4]uint64{
+       0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b,
+       0x63aa97a331b4f2ee, 0x3d217f5be65cb5c,
+}}
+
+// setShortBytes sets s = x mod l, where x is a little-endian integer shorter
+// than 32 bytes.
+func (s *Scalar) setShortBytes(x []byte) *Scalar {
+       if len(x) >= 32 {
+               panic("edwards25519: internal error: setShortBytes called with a long string")
+       }
+       var buf [32]byte
+       copy(buf[:], x)
+       fiatScalarFromBytes((*[4]uint64)(&s.s), &buf)
+       fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
+       return s
+}
+
+// SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of
+// s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes
+// returns nil and an error, and the receiver is unchanged.
+func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) {
+       if len(x) != 32 {
+               return nil, errors.New("invalid scalar length")
+       }
+       if !isReduced(x) {
+               return nil, errors.New("invalid scalar encoding")
+       }
+
+       fiatScalarFromBytes((*[4]uint64)(&s.s), (*[32]byte)(x))
+       fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
+
+       return s, nil
+}
+
+// scalarMinusOneBytes is l - 1 in little endian.
+var scalarMinusOneBytes = [32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}
+
+// isReduced returns whether the given scalar in 32-byte little endian encoded
+// form is reduced modulo l.
+func isReduced(s []byte) bool {
+       if len(s) != 32 {
+               return false
+       }
+
+       for i := len(s) - 1; i >= 0; i-- {
+               switch {
+               case s[i] > scalarMinusOneBytes[i]:
+                       return false
+               case s[i] < scalarMinusOneBytes[i]:
+                       return true
+               }
+       }
+       return true
+}
+
+// SetBytesWithClamping applies the buffer pruning described in RFC 8032,
+// Section 5.1.5 (also known as clamping) and sets s to the result. The input
+// must be 32 bytes, and it is not modified. If x is not of the right length,
+// SetBytesWithClamping returns nil and an error, and the receiver is unchanged.
+//
+// Note that since Scalar values are always reduced modulo the prime order of
+// the curve, the resulting value will not preserve any of the cofactor-clearing
+// properties that clamping is meant to provide. It will however work as
+// expected as long as it is applied to points on the prime order subgroup, like
+// in Ed25519. In fact, it is lost to history why RFC 8032 adopted the
+// irrelevant RFC 7748 clamping, but it is now required for compatibility.
+func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) {
+       // The description above omits the purpose of the high bits of the clamping
+       // for brevity, but those are also lost to reductions, and are also
+       // irrelevant to edwards25519 as they protect against a specific
+       // implementation bug that was once observed in a generic Montgomery ladder.
+       if len(x) != 32 {
+               return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length")
+       }
+
+       // We need to use the wide reduction from SetUniformBytes, since clamping
+       // sets the 2^254 bit, making the value higher than the order.
+       var wideBytes [64]byte
+       copy(wideBytes[:], x[:])
+       wideBytes[0] &= 248
+       wideBytes[31] &= 63
+       wideBytes[31] |= 64
+       return s.SetUniformBytes(wideBytes[:])
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of s.
+func (s *Scalar) Bytes() []byte {
+       // This function is outlined to make the allocations inline in the caller
+       // rather than happen on the heap.
+       var encoded [32]byte
+       return s.bytes(&encoded)
+}
+
+func (s *Scalar) bytes(out *[32]byte) []byte {
+       var ss fiatScalarNonMontgomeryDomainFieldElement
+       fiatScalarFromMontgomery(&ss, &s.s)
+       fiatScalarToBytes(out, (*[4]uint64)(&ss))
+       return out[:]
+}
+
+// Equal returns 1 if s and t are equal, and 0 otherwise.
+func (s *Scalar) Equal(t *Scalar) int {
+       var diff fiatScalarMontgomeryDomainFieldElement
+       fiatScalarSub(&diff, &s.s, &t.s)
+       var nonzero uint64
+       fiatScalarNonzero(&nonzero, (*[4]uint64)(&diff))
+       nonzero |= nonzero >> 32
+       nonzero |= nonzero >> 16
+       nonzero |= nonzero >> 8
+       nonzero |= nonzero >> 4
+       nonzero |= nonzero >> 2
+       nonzero |= nonzero >> 1
+       return int(^nonzero) & 1
+}
+
+// nonAdjacentForm computes a width-w non-adjacent form for this scalar.
+//
+// w must be between 2 and 8, or nonAdjacentForm will panic.
+func (s *Scalar) nonAdjacentForm(w uint) [256]int8 {
+       // This implementation is adapted from the one
+       // in curve25519-dalek and is documented there:
+       // https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871
+       b := s.Bytes()
+       if b[31] > 127 {
+               panic("scalar has high bit set illegally")
+       }
+       if w < 2 {
+               panic("w must be at least 2 by the definition of NAF")
+       } else if w > 8 {
+               panic("NAF digits must fit in int8")
+       }
+
+       var naf [256]int8
+       var digits [5]uint64
+
+       for i := 0; i < 4; i++ {
+               digits[i] = byteorder.LEUint64(b[i*8:])
+       }
+
+       width := uint64(1 << w)
+       windowMask := uint64(width - 1)
+
+       pos := uint(0)
+       carry := uint64(0)
+       for pos < 256 {
+               indexU64 := pos / 64
+               indexBit := pos % 64
+               var bitBuf uint64
+               if indexBit < 64-w {
+                       // This window's bits are contained in a single u64
+                       bitBuf = digits[indexU64] >> indexBit
+               } else {
+                       // Combine the current 64 bits with bits from the next 64
+                       bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit))
+               }
+
+               // Add carry into the current window
+               window := carry + (bitBuf & windowMask)
+
+               if window&1 == 0 {
+                       // If the window value is even, preserve the carry and continue.
+                       // Why is the carry preserved?
+                       // If carry == 0 and window & 1 == 0,
+                       //    then the next carry should be 0
+                       // If carry == 1 and window & 1 == 0,
+                       //    then bit_buf & 1 == 1 so the next carry should be 1
+                       pos += 1
+                       continue
+               }
+
+               if window < width/2 {
+                       carry = 0
+                       naf[pos] = int8(window)
+               } else {
+                       carry = 1
+                       naf[pos] = int8(window) - int8(width)
+               }
+
+               pos += w
+       }
+       return naf
+}
+
+func (s *Scalar) signedRadix16() [64]int8 {
+       b := s.Bytes()
+       if b[31] > 127 {
+               panic("scalar has high bit set illegally")
+       }
+
+       var digits [64]int8
+
+       // Compute unsigned radix-16 digits:
+       for i := 0; i < 32; i++ {
+               digits[2*i] = int8(b[i] & 15)
+               digits[2*i+1] = int8((b[i] >> 4) & 15)
+       }
+
+       // Recenter coefficients:
+       for i := 0; i < 63; i++ {
+               carry := (digits[i] + 8) >> 4
+               digits[i] -= carry << 4
+               digits[i+1] += carry
+       }
+
+       return digits
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/scalar_fiat.go b/go/cm/sign/ed25519-blake2b/edwards25519/scalar_fiat.go
new file mode 100644 (file)
index 0000000..c863eb9
--- /dev/null
@@ -0,0 +1,1147 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name edwards25519 Scalar 64 '2^252 + 27742317777372353535851937790883648493' mul add sub opp nonzero from_montgomery to_montgomery to_bytes from_bytes
+//
+// curve description: Scalar
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, add, sub, opp, nonzero, from_montgomery, to_montgomery, to_bytes, from_bytes
+//
+// m = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed (from "2^252 + 27742317777372353535851937790883648493")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+//   functions synthesized for this Montgomery arithmetic require the
+//
+//   input to be strictly less than the prime modulus (m), and also
+//
+//   require the input to be in the unique saturated representation.
+//
+//   All functions also ensure that these two properties are true of
+//
+//   return values.
+//
+//
+//
+// Computed values:
+//
+//   eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
+//
+//   bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
+//
+//   twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
+//
+//                            if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
+
+package edwards25519
+
+import "math/bits"
+
+type fiatScalarUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type fiatScalarInt1 int64   // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type fiatScalarMontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type fiatScalarMontgomeryDomainFieldElement [4]uint64
+
+// The type fiatScalarNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type fiatScalarNonMontgomeryDomainFieldElement [4]uint64
+
+// fiatScalarCmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+//     out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+//     arg1: [0x0 ~> 0x1]
+//     arg2: [0x0 ~> 0xffffffffffffffff]
+//     arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+//     out1: [0x0 ~> 0xffffffffffffffff]
+func fiatScalarCmovznzU64(out1 *uint64, arg1 fiatScalarUint1, arg2 uint64, arg3 uint64) {
+       x1 := (uint64(arg1) * 0xffffffffffffffff)
+       x2 := ((x1 & arg3) | ((^x1) & arg2))
+       *out1 = x2
+}
+
+// fiatScalarMul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//     0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+//     eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+//     0 ≤ eval out1 < m
+func fiatScalarMul(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+       x1 := arg1[1]
+       x2 := arg1[2]
+       x3 := arg1[3]
+       x4 := arg1[0]
+       var x5 uint64
+       var x6 uint64
+       x6, x5 = bits.Mul64(x4, arg2[3])
+       var x7 uint64
+       var x8 uint64
+       x8, x7 = bits.Mul64(x4, arg2[2])
+       var x9 uint64
+       var x10 uint64
+       x10, x9 = bits.Mul64(x4, arg2[1])
+       var x11 uint64
+       var x12 uint64
+       x12, x11 = bits.Mul64(x4, arg2[0])
+       var x13 uint64
+       var x14 uint64
+       x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+       var x15 uint64
+       var x16 uint64
+       x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14)))
+       var x17 uint64
+       var x18 uint64
+       x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16)))
+       x19 := (uint64(fiatScalarUint1(x18)) + x6)
+       var x20 uint64
+       _, x20 = bits.Mul64(x11, 0xd2b51da312547e1b)
+       var x22 uint64
+       var x23 uint64
+       x23, x22 = bits.Mul64(x20, 0x1000000000000000)
+       var x24 uint64
+       var x25 uint64
+       x25, x24 = bits.Mul64(x20, 0x14def9dea2f79cd6)
+       var x26 uint64
+       var x27 uint64
+       x27, x26 = bits.Mul64(x20, 0x5812631a5cf5d3ed)
+       var x28 uint64
+       var x29 uint64
+       x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+       x30 := (uint64(fiatScalarUint1(x29)) + x25)
+       var x32 uint64
+       _, x32 = bits.Add64(x11, x26, uint64(0x0))
+       var x33 uint64
+       var x34 uint64
+       x33, x34 = bits.Add64(x13, x28, uint64(fiatScalarUint1(x32)))
+       var x35 uint64
+       var x36 uint64
+       x35, x36 = bits.Add64(x15, x30, uint64(fiatScalarUint1(x34)))
+       var x37 uint64
+       var x38 uint64
+       x37, x38 = bits.Add64(x17, x22, uint64(fiatScalarUint1(x36)))
+       var x39 uint64
+       var x40 uint64
+       x39, x40 = bits.Add64(x19, x23, uint64(fiatScalarUint1(x38)))
+       var x41 uint64
+       var x42 uint64
+       x42, x41 = bits.Mul64(x1, arg2[3])
+       var x43 uint64
+       var x44 uint64
+       x44, x43 = bits.Mul64(x1, arg2[2])
+       var x45 uint64
+       var x46 uint64
+       x46, x45 = bits.Mul64(x1, arg2[1])
+       var x47 uint64
+       var x48 uint64
+       x48, x47 = bits.Mul64(x1, arg2[0])
+       var x49 uint64
+       var x50 uint64
+       x49, x50 = bits.Add64(x48, x45, uint64(0x0))
+       var x51 uint64
+       var x52 uint64
+       x51, x52 = bits.Add64(x46, x43, uint64(fiatScalarUint1(x50)))
+       var x53 uint64
+       var x54 uint64
+       x53, x54 = bits.Add64(x44, x41, uint64(fiatScalarUint1(x52)))
+       x55 := (uint64(fiatScalarUint1(x54)) + x42)
+       var x56 uint64
+       var x57 uint64
+       x56, x57 = bits.Add64(x33, x47, uint64(0x0))
+       var x58 uint64
+       var x59 uint64
+       x58, x59 = bits.Add64(x35, x49, uint64(fiatScalarUint1(x57)))
+       var x60 uint64
+       var x61 uint64
+       x60, x61 = bits.Add64(x37, x51, uint64(fiatScalarUint1(x59)))
+       var x62 uint64
+       var x63 uint64
+       x62, x63 = bits.Add64(x39, x53, uint64(fiatScalarUint1(x61)))
+       var x64 uint64
+       var x65 uint64
+       x64, x65 = bits.Add64(uint64(fiatScalarUint1(x40)), x55, uint64(fiatScalarUint1(x63)))
+       var x66 uint64
+       _, x66 = bits.Mul64(x56, 0xd2b51da312547e1b)
+       var x68 uint64
+       var x69 uint64
+       x69, x68 = bits.Mul64(x66, 0x1000000000000000)
+       var x70 uint64
+       var x71 uint64
+       x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6)
+       var x72 uint64
+       var x73 uint64
+       x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed)
+       var x74 uint64
+       var x75 uint64
+       x74, x75 = bits.Add64(x73, x70, uint64(0x0))
+       x76 := (uint64(fiatScalarUint1(x75)) + x71)
+       var x78 uint64
+       _, x78 = bits.Add64(x56, x72, uint64(0x0))
+       var x79 uint64
+       var x80 uint64
+       x79, x80 = bits.Add64(x58, x74, uint64(fiatScalarUint1(x78)))
+       var x81 uint64
+       var x82 uint64
+       x81, x82 = bits.Add64(x60, x76, uint64(fiatScalarUint1(x80)))
+       var x83 uint64
+       var x84 uint64
+       x83, x84 = bits.Add64(x62, x68, uint64(fiatScalarUint1(x82)))
+       var x85 uint64
+       var x86 uint64
+       x85, x86 = bits.Add64(x64, x69, uint64(fiatScalarUint1(x84)))
+       x87 := (uint64(fiatScalarUint1(x86)) + uint64(fiatScalarUint1(x65)))
+       var x88 uint64
+       var x89 uint64
+       x89, x88 = bits.Mul64(x2, arg2[3])
+       var x90 uint64
+       var x91 uint64
+       x91, x90 = bits.Mul64(x2, arg2[2])
+       var x92 uint64
+       var x93 uint64
+       x93, x92 = bits.Mul64(x2, arg2[1])
+       var x94 uint64
+       var x95 uint64
+       x95, x94 = bits.Mul64(x2, arg2[0])
+       var x96 uint64
+       var x97 uint64
+       x96, x97 = bits.Add64(x95, x92, uint64(0x0))
+       var x98 uint64
+       var x99 uint64
+       x98, x99 = bits.Add64(x93, x90, uint64(fiatScalarUint1(x97)))
+       var x100 uint64
+       var x101 uint64
+       x100, x101 = bits.Add64(x91, x88, uint64(fiatScalarUint1(x99)))
+       x102 := (uint64(fiatScalarUint1(x101)) + x89)
+       var x103 uint64
+       var x104 uint64
+       x103, x104 = bits.Add64(x79, x94, uint64(0x0))
+       var x105 uint64
+       var x106 uint64
+       x105, x106 = bits.Add64(x81, x96, uint64(fiatScalarUint1(x104)))
+       var x107 uint64
+       var x108 uint64
+       x107, x108 = bits.Add64(x83, x98, uint64(fiatScalarUint1(x106)))
+       var x109 uint64
+       var x110 uint64
+       x109, x110 = bits.Add64(x85, x100, uint64(fiatScalarUint1(x108)))
+       var x111 uint64
+       var x112 uint64
+       x111, x112 = bits.Add64(x87, x102, uint64(fiatScalarUint1(x110)))
+       var x113 uint64
+       _, x113 = bits.Mul64(x103, 0xd2b51da312547e1b)
+       var x115 uint64
+       var x116 uint64
+       x116, x115 = bits.Mul64(x113, 0x1000000000000000)
+       var x117 uint64
+       var x118 uint64
+       x118, x117 = bits.Mul64(x113, 0x14def9dea2f79cd6)
+       var x119 uint64
+       var x120 uint64
+       x120, x119 = bits.Mul64(x113, 0x5812631a5cf5d3ed)
+       var x121 uint64
+       var x122 uint64
+       x121, x122 = bits.Add64(x120, x117, uint64(0x0))
+       x123 := (uint64(fiatScalarUint1(x122)) + x118)
+       var x125 uint64
+       _, x125 = bits.Add64(x103, x119, uint64(0x0))
+       var x126 uint64
+       var x127 uint64
+       x126, x127 = bits.Add64(x105, x121, uint64(fiatScalarUint1(x125)))
+       var x128 uint64
+       var x129 uint64
+       x128, x129 = bits.Add64(x107, x123, uint64(fiatScalarUint1(x127)))
+       var x130 uint64
+       var x131 uint64
+       x130, x131 = bits.Add64(x109, x115, uint64(fiatScalarUint1(x129)))
+       var x132 uint64
+       var x133 uint64
+       x132, x133 = bits.Add64(x111, x116, uint64(fiatScalarUint1(x131)))
+       x134 := (uint64(fiatScalarUint1(x133)) + uint64(fiatScalarUint1(x112)))
+       var x135 uint64
+       var x136 uint64
+       x136, x135 = bits.Mul64(x3, arg2[3])
+       var x137 uint64
+       var x138 uint64
+       x138, x137 = bits.Mul64(x3, arg2[2])
+       var x139 uint64
+       var x140 uint64
+       x140, x139 = bits.Mul64(x3, arg2[1])
+       var x141 uint64
+       var x142 uint64
+       x142, x141 = bits.Mul64(x3, arg2[0])
+       var x143 uint64
+       var x144 uint64
+       x143, x144 = bits.Add64(x142, x139, uint64(0x0))
+       var x145 uint64
+       var x146 uint64
+       x145, x146 = bits.Add64(x140, x137, uint64(fiatScalarUint1(x144)))
+       var x147 uint64
+       var x148 uint64
+       x147, x148 = bits.Add64(x138, x135, uint64(fiatScalarUint1(x146)))
+       x149 := (uint64(fiatScalarUint1(x148)) + x136)
+       var x150 uint64
+       var x151 uint64
+       x150, x151 = bits.Add64(x126, x141, uint64(0x0))
+       var x152 uint64
+       var x153 uint64
+       x152, x153 = bits.Add64(x128, x143, uint64(fiatScalarUint1(x151)))
+       var x154 uint64
+       var x155 uint64
+       x154, x155 = bits.Add64(x130, x145, uint64(fiatScalarUint1(x153)))
+       var x156 uint64
+       var x157 uint64
+       x156, x157 = bits.Add64(x132, x147, uint64(fiatScalarUint1(x155)))
+       var x158 uint64
+       var x159 uint64
+       x158, x159 = bits.Add64(x134, x149, uint64(fiatScalarUint1(x157)))
+       var x160 uint64
+       _, x160 = bits.Mul64(x150, 0xd2b51da312547e1b)
+       var x162 uint64
+       var x163 uint64
+       x163, x162 = bits.Mul64(x160, 0x1000000000000000)
+       var x164 uint64
+       var x165 uint64
+       x165, x164 = bits.Mul64(x160, 0x14def9dea2f79cd6)
+       var x166 uint64
+       var x167 uint64
+       x167, x166 = bits.Mul64(x160, 0x5812631a5cf5d3ed)
+       var x168 uint64
+       var x169 uint64
+       x168, x169 = bits.Add64(x167, x164, uint64(0x0))
+       x170 := (uint64(fiatScalarUint1(x169)) + x165)
+       var x172 uint64
+       _, x172 = bits.Add64(x150, x166, uint64(0x0))
+       var x173 uint64
+       var x174 uint64
+       x173, x174 = bits.Add64(x152, x168, uint64(fiatScalarUint1(x172)))
+       var x175 uint64
+       var x176 uint64
+       x175, x176 = bits.Add64(x154, x170, uint64(fiatScalarUint1(x174)))
+       var x177 uint64
+       var x178 uint64
+       x177, x178 = bits.Add64(x156, x162, uint64(fiatScalarUint1(x176)))
+       var x179 uint64
+       var x180 uint64
+       x179, x180 = bits.Add64(x158, x163, uint64(fiatScalarUint1(x178)))
+       x181 := (uint64(fiatScalarUint1(x180)) + uint64(fiatScalarUint1(x159)))
+       var x182 uint64
+       var x183 uint64
+       x182, x183 = bits.Sub64(x173, 0x5812631a5cf5d3ed, uint64(0x0))
+       var x184 uint64
+       var x185 uint64
+       x184, x185 = bits.Sub64(x175, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x183)))
+       var x186 uint64
+       var x187 uint64
+       x186, x187 = bits.Sub64(x177, uint64(0x0), uint64(fiatScalarUint1(x185)))
+       var x188 uint64
+       var x189 uint64
+       x188, x189 = bits.Sub64(x179, 0x1000000000000000, uint64(fiatScalarUint1(x187)))
+       var x191 uint64
+       _, x191 = bits.Sub64(x181, uint64(0x0), uint64(fiatScalarUint1(x189)))
+       var x192 uint64
+       fiatScalarCmovznzU64(&x192, fiatScalarUint1(x191), x182, x173)
+       var x193 uint64
+       fiatScalarCmovznzU64(&x193, fiatScalarUint1(x191), x184, x175)
+       var x194 uint64
+       fiatScalarCmovznzU64(&x194, fiatScalarUint1(x191), x186, x177)
+       var x195 uint64
+       fiatScalarCmovznzU64(&x195, fiatScalarUint1(x191), x188, x179)
+       out1[0] = x192
+       out1[1] = x193
+       out1[2] = x194
+       out1[3] = x195
+}
+
+// fiatScalarAdd adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//     0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+//     eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+//     0 ≤ eval out1 < m
+func fiatScalarAdd(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+       var x1 uint64
+       var x2 uint64
+       x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+       var x3 uint64
+       var x4 uint64
+       x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2)))
+       var x5 uint64
+       var x6 uint64
+       x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4)))
+       var x7 uint64
+       var x8 uint64
+       x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6)))
+       var x9 uint64
+       var x10 uint64
+       x9, x10 = bits.Sub64(x1, 0x5812631a5cf5d3ed, uint64(0x0))
+       var x11 uint64
+       var x12 uint64
+       x11, x12 = bits.Sub64(x3, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x10)))
+       var x13 uint64
+       var x14 uint64
+       x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(fiatScalarUint1(x12)))
+       var x15 uint64
+       var x16 uint64
+       x15, x16 = bits.Sub64(x7, 0x1000000000000000, uint64(fiatScalarUint1(x14)))
+       var x18 uint64
+       _, x18 = bits.Sub64(uint64(fiatScalarUint1(x8)), uint64(0x0), uint64(fiatScalarUint1(x16)))
+       var x19 uint64
+       fiatScalarCmovznzU64(&x19, fiatScalarUint1(x18), x9, x1)
+       var x20 uint64
+       fiatScalarCmovznzU64(&x20, fiatScalarUint1(x18), x11, x3)
+       var x21 uint64
+       fiatScalarCmovznzU64(&x21, fiatScalarUint1(x18), x13, x5)
+       var x22 uint64
+       fiatScalarCmovznzU64(&x22, fiatScalarUint1(x18), x15, x7)
+       out1[0] = x19
+       out1[1] = x20
+       out1[2] = x21
+       out1[3] = x22
+}
+
+// fiatScalarSub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//     0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+//     eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+//     0 ≤ eval out1 < m
+func fiatScalarSub(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+       var x1 uint64
+       var x2 uint64
+       x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+       var x3 uint64
+       var x4 uint64
+       x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2)))
+       var x5 uint64
+       var x6 uint64
+       x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4)))
+       var x7 uint64
+       var x8 uint64
+       x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6)))
+       var x9 uint64
+       fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff)
+       var x10 uint64
+       var x11 uint64
+       x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0))
+       var x12 uint64
+       var x13 uint64
+       x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11)))
+       var x14 uint64
+       var x15 uint64
+       x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13)))
+       var x16 uint64
+       x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15)))
+       out1[0] = x10
+       out1[1] = x12
+       out1[2] = x14
+       out1[3] = x16
+}
+
+// fiatScalarOpp negates a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+//     eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
+//     0 ≤ eval out1 < m
+func fiatScalarOpp(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) {
+       var x1 uint64
+       var x2 uint64
+       x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0))
+       var x3 uint64
+       var x4 uint64
+       x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(fiatScalarUint1(x2)))
+       var x5 uint64
+       var x6 uint64
+       x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(fiatScalarUint1(x4)))
+       var x7 uint64
+       var x8 uint64
+       x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(fiatScalarUint1(x6)))
+       var x9 uint64
+       fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff)
+       var x10 uint64
+       var x11 uint64
+       x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0))
+       var x12 uint64
+       var x13 uint64
+       x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11)))
+       var x14 uint64
+       var x15 uint64
+       x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13)))
+       var x16 uint64
+       x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15)))
+       out1[0] = x10
+       out1[1] = x12
+       out1[2] = x14
+       out1[3] = x16
+}
+
+// fiatScalarNonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+//     out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
+//
+// Input Bounds:
+//
+//     arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+//     out1: [0x0 ~> 0xffffffffffffffff]
+func fiatScalarNonzero(out1 *uint64, arg1 *[4]uint64) {
+       x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3])))
+       *out1 = x1
+}
+
+// fiatScalarFromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+//     eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
+//     0 ≤ eval out1 < m
+func fiatScalarFromMontgomery(out1 *fiatScalarNonMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) {
+       x1 := arg1[0]
+       var x2 uint64
+       _, x2 = bits.Mul64(x1, 0xd2b51da312547e1b)
+       var x4 uint64
+       var x5 uint64
+       x5, x4 = bits.Mul64(x2, 0x1000000000000000)
+       var x6 uint64
+       var x7 uint64
+       x7, x6 = bits.Mul64(x2, 0x14def9dea2f79cd6)
+       var x8 uint64
+       var x9 uint64
+       x9, x8 = bits.Mul64(x2, 0x5812631a5cf5d3ed)
+       var x10 uint64
+       var x11 uint64
+       x10, x11 = bits.Add64(x9, x6, uint64(0x0))
+       var x13 uint64
+       _, x13 = bits.Add64(x1, x8, uint64(0x0))
+       var x14 uint64
+       var x15 uint64
+       x14, x15 = bits.Add64(uint64(0x0), x10, uint64(fiatScalarUint1(x13)))
+       var x16 uint64
+       var x17 uint64
+       x16, x17 = bits.Add64(x14, arg1[1], uint64(0x0))
+       var x18 uint64
+       _, x18 = bits.Mul64(x16, 0xd2b51da312547e1b)
+       var x20 uint64
+       var x21 uint64
+       x21, x20 = bits.Mul64(x18, 0x1000000000000000)
+       var x22 uint64
+       var x23 uint64
+       x23, x22 = bits.Mul64(x18, 0x14def9dea2f79cd6)
+       var x24 uint64
+       var x25 uint64
+       x25, x24 = bits.Mul64(x18, 0x5812631a5cf5d3ed)
+       var x26 uint64
+       var x27 uint64
+       x26, x27 = bits.Add64(x25, x22, uint64(0x0))
+       var x29 uint64
+       _, x29 = bits.Add64(x16, x24, uint64(0x0))
+       var x30 uint64
+       var x31 uint64
+       x30, x31 = bits.Add64((uint64(fiatScalarUint1(x17)) + (uint64(fiatScalarUint1(x15)) + (uint64(fiatScalarUint1(x11)) + x7))), x26, uint64(fiatScalarUint1(x29)))
+       var x32 uint64
+       var x33 uint64
+       x32, x33 = bits.Add64(x4, (uint64(fiatScalarUint1(x27)) + x23), uint64(fiatScalarUint1(x31)))
+       var x34 uint64
+       var x35 uint64
+       x34, x35 = bits.Add64(x5, x20, uint64(fiatScalarUint1(x33)))
+       var x36 uint64
+       var x37 uint64
+       x36, x37 = bits.Add64(x30, arg1[2], uint64(0x0))
+       var x38 uint64
+       var x39 uint64
+       x38, x39 = bits.Add64(x32, uint64(0x0), uint64(fiatScalarUint1(x37)))
+       var x40 uint64
+       var x41 uint64
+       x40, x41 = bits.Add64(x34, uint64(0x0), uint64(fiatScalarUint1(x39)))
+       var x42 uint64
+       _, x42 = bits.Mul64(x36, 0xd2b51da312547e1b)
+       var x44 uint64
+       var x45 uint64
+       x45, x44 = bits.Mul64(x42, 0x1000000000000000)
+       var x46 uint64
+       var x47 uint64
+       x47, x46 = bits.Mul64(x42, 0x14def9dea2f79cd6)
+       var x48 uint64
+       var x49 uint64
+       x49, x48 = bits.Mul64(x42, 0x5812631a5cf5d3ed)
+       var x50 uint64
+       var x51 uint64
+       x50, x51 = bits.Add64(x49, x46, uint64(0x0))
+       var x53 uint64
+       _, x53 = bits.Add64(x36, x48, uint64(0x0))
+       var x54 uint64
+       var x55 uint64
+       x54, x55 = bits.Add64(x38, x50, uint64(fiatScalarUint1(x53)))
+       var x56 uint64
+       var x57 uint64
+       x56, x57 = bits.Add64(x40, (uint64(fiatScalarUint1(x51)) + x47), uint64(fiatScalarUint1(x55)))
+       var x58 uint64
+       var x59 uint64
+       x58, x59 = bits.Add64((uint64(fiatScalarUint1(x41)) + (uint64(fiatScalarUint1(x35)) + x21)), x44, uint64(fiatScalarUint1(x57)))
+       var x60 uint64
+       var x61 uint64
+       x60, x61 = bits.Add64(x54, arg1[3], uint64(0x0))
+       var x62 uint64
+       var x63 uint64
+       x62, x63 = bits.Add64(x56, uint64(0x0), uint64(fiatScalarUint1(x61)))
+       var x64 uint64
+       var x65 uint64
+       x64, x65 = bits.Add64(x58, uint64(0x0), uint64(fiatScalarUint1(x63)))
+       var x66 uint64
+       _, x66 = bits.Mul64(x60, 0xd2b51da312547e1b)
+       var x68 uint64
+       var x69 uint64
+       x69, x68 = bits.Mul64(x66, 0x1000000000000000)
+       var x70 uint64
+       var x71 uint64
+       x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6)
+       var x72 uint64
+       var x73 uint64
+       x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed)
+       var x74 uint64
+       var x75 uint64
+       x74, x75 = bits.Add64(x73, x70, uint64(0x0))
+       var x77 uint64
+       _, x77 = bits.Add64(x60, x72, uint64(0x0))
+       var x78 uint64
+       var x79 uint64
+       x78, x79 = bits.Add64(x62, x74, uint64(fiatScalarUint1(x77)))
+       var x80 uint64
+       var x81 uint64
+       x80, x81 = bits.Add64(x64, (uint64(fiatScalarUint1(x75)) + x71), uint64(fiatScalarUint1(x79)))
+       var x82 uint64
+       var x83 uint64
+       x82, x83 = bits.Add64((uint64(fiatScalarUint1(x65)) + (uint64(fiatScalarUint1(x59)) + x45)), x68, uint64(fiatScalarUint1(x81)))
+       x84 := (uint64(fiatScalarUint1(x83)) + x69)
+       var x85 uint64
+       var x86 uint64
+       x85, x86 = bits.Sub64(x78, 0x5812631a5cf5d3ed, uint64(0x0))
+       var x87 uint64
+       var x88 uint64
+       x87, x88 = bits.Sub64(x80, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x86)))
+       var x89 uint64
+       var x90 uint64
+       x89, x90 = bits.Sub64(x82, uint64(0x0), uint64(fiatScalarUint1(x88)))
+       var x91 uint64
+       var x92 uint64
+       x91, x92 = bits.Sub64(x84, 0x1000000000000000, uint64(fiatScalarUint1(x90)))
+       var x94 uint64
+       _, x94 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x92)))
+       var x95 uint64
+       fiatScalarCmovznzU64(&x95, fiatScalarUint1(x94), x85, x78)
+       var x96 uint64
+       fiatScalarCmovznzU64(&x96, fiatScalarUint1(x94), x87, x80)
+       var x97 uint64
+       fiatScalarCmovznzU64(&x97, fiatScalarUint1(x94), x89, x82)
+       var x98 uint64
+       fiatScalarCmovznzU64(&x98, fiatScalarUint1(x94), x91, x84)
+       out1[0] = x95
+       out1[1] = x96
+       out1[2] = x97
+       out1[3] = x98
+}
+
+// fiatScalarToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+//     eval (from_montgomery out1) mod m = eval arg1 mod m
+//     0 ≤ eval out1 < m
+func fiatScalarToMontgomery(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarNonMontgomeryDomainFieldElement) {
+       x1 := arg1[1]
+       x2 := arg1[2]
+       x3 := arg1[3]
+       x4 := arg1[0]
+       var x5 uint64
+       var x6 uint64
+       x6, x5 = bits.Mul64(x4, 0x399411b7c309a3d)
+       var x7 uint64
+       var x8 uint64
+       x8, x7 = bits.Mul64(x4, 0xceec73d217f5be65)
+       var x9 uint64
+       var x10 uint64
+       x10, x9 = bits.Mul64(x4, 0xd00e1ba768859347)
+       var x11 uint64
+       var x12 uint64
+       x12, x11 = bits.Mul64(x4, 0xa40611e3449c0f01)
+       var x13 uint64
+       var x14 uint64
+       x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+       var x15 uint64
+       var x16 uint64
+       x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14)))
+       var x17 uint64
+       var x18 uint64
+       x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16)))
+       var x19 uint64
+       _, x19 = bits.Mul64(x11, 0xd2b51da312547e1b)
+       var x21 uint64
+       var x22 uint64
+       x22, x21 = bits.Mul64(x19, 0x1000000000000000)
+       var x23 uint64
+       var x24 uint64
+       x24, x23 = bits.Mul64(x19, 0x14def9dea2f79cd6)
+       var x25 uint64
+       var x26 uint64
+       x26, x25 = bits.Mul64(x19, 0x5812631a5cf5d3ed)
+       var x27 uint64
+       var x28 uint64
+       x27, x28 = bits.Add64(x26, x23, uint64(0x0))
+       var x30 uint64
+       _, x30 = bits.Add64(x11, x25, uint64(0x0))
+       var x31 uint64
+       var x32 uint64
+       x31, x32 = bits.Add64(x13, x27, uint64(fiatScalarUint1(x30)))
+       var x33 uint64
+       var x34 uint64
+       x33, x34 = bits.Add64(x15, (uint64(fiatScalarUint1(x28)) + x24), uint64(fiatScalarUint1(x32)))
+       var x35 uint64
+       var x36 uint64
+       x35, x36 = bits.Add64(x17, x21, uint64(fiatScalarUint1(x34)))
+       var x37 uint64
+       var x38 uint64
+       x38, x37 = bits.Mul64(x1, 0x399411b7c309a3d)
+       var x39 uint64
+       var x40 uint64
+       x40, x39 = bits.Mul64(x1, 0xceec73d217f5be65)
+       var x41 uint64
+       var x42 uint64
+       x42, x41 = bits.Mul64(x1, 0xd00e1ba768859347)
+       var x43 uint64
+       var x44 uint64
+       x44, x43 = bits.Mul64(x1, 0xa40611e3449c0f01)
+       var x45 uint64
+       var x46 uint64
+       x45, x46 = bits.Add64(x44, x41, uint64(0x0))
+       var x47 uint64
+       var x48 uint64
+       x47, x48 = bits.Add64(x42, x39, uint64(fiatScalarUint1(x46)))
+       var x49 uint64
+       var x50 uint64
+       x49, x50 = bits.Add64(x40, x37, uint64(fiatScalarUint1(x48)))
+       var x51 uint64
+       var x52 uint64
+       x51, x52 = bits.Add64(x31, x43, uint64(0x0))
+       var x53 uint64
+       var x54 uint64
+       x53, x54 = bits.Add64(x33, x45, uint64(fiatScalarUint1(x52)))
+       var x55 uint64
+       var x56 uint64
+       x55, x56 = bits.Add64(x35, x47, uint64(fiatScalarUint1(x54)))
+       var x57 uint64
+       var x58 uint64
+       x57, x58 = bits.Add64(((uint64(fiatScalarUint1(x36)) + (uint64(fiatScalarUint1(x18)) + x6)) + x22), x49, uint64(fiatScalarUint1(x56)))
+       var x59 uint64
+       _, x59 = bits.Mul64(x51, 0xd2b51da312547e1b)
+       var x61 uint64
+       var x62 uint64
+       x62, x61 = bits.Mul64(x59, 0x1000000000000000)
+       var x63 uint64
+       var x64 uint64
+       x64, x63 = bits.Mul64(x59, 0x14def9dea2f79cd6)
+       var x65 uint64
+       var x66 uint64
+       x66, x65 = bits.Mul64(x59, 0x5812631a5cf5d3ed)
+       var x67 uint64
+       var x68 uint64
+       x67, x68 = bits.Add64(x66, x63, uint64(0x0))
+       var x70 uint64
+       _, x70 = bits.Add64(x51, x65, uint64(0x0))
+       var x71 uint64
+       var x72 uint64
+       x71, x72 = bits.Add64(x53, x67, uint64(fiatScalarUint1(x70)))
+       var x73 uint64
+       var x74 uint64
+       x73, x74 = bits.Add64(x55, (uint64(fiatScalarUint1(x68)) + x64), uint64(fiatScalarUint1(x72)))
+       var x75 uint64
+       var x76 uint64
+       x75, x76 = bits.Add64(x57, x61, uint64(fiatScalarUint1(x74)))
+       var x77 uint64
+       var x78 uint64
+       x78, x77 = bits.Mul64(x2, 0x399411b7c309a3d)
+       var x79 uint64
+       var x80 uint64
+       x80, x79 = bits.Mul64(x2, 0xceec73d217f5be65)
+       var x81 uint64
+       var x82 uint64
+       x82, x81 = bits.Mul64(x2, 0xd00e1ba768859347)
+       var x83 uint64
+       var x84 uint64
+       x84, x83 = bits.Mul64(x2, 0xa40611e3449c0f01)
+       var x85 uint64
+       var x86 uint64
+       x85, x86 = bits.Add64(x84, x81, uint64(0x0))
+       var x87 uint64
+       var x88 uint64
+       x87, x88 = bits.Add64(x82, x79, uint64(fiatScalarUint1(x86)))
+       var x89 uint64
+       var x90 uint64
+       x89, x90 = bits.Add64(x80, x77, uint64(fiatScalarUint1(x88)))
+       var x91 uint64
+       var x92 uint64
+       x91, x92 = bits.Add64(x71, x83, uint64(0x0))
+       var x93 uint64
+       var x94 uint64
+       x93, x94 = bits.Add64(x73, x85, uint64(fiatScalarUint1(x92)))
+       var x95 uint64
+       var x96 uint64
+       x95, x96 = bits.Add64(x75, x87, uint64(fiatScalarUint1(x94)))
+       var x97 uint64
+       var x98 uint64
+       x97, x98 = bits.Add64(((uint64(fiatScalarUint1(x76)) + (uint64(fiatScalarUint1(x58)) + (uint64(fiatScalarUint1(x50)) + x38))) + x62), x89, uint64(fiatScalarUint1(x96)))
+       var x99 uint64
+       _, x99 = bits.Mul64(x91, 0xd2b51da312547e1b)
+       var x101 uint64
+       var x102 uint64
+       x102, x101 = bits.Mul64(x99, 0x1000000000000000)
+       var x103 uint64
+       var x104 uint64
+       x104, x103 = bits.Mul64(x99, 0x14def9dea2f79cd6)
+       var x105 uint64
+       var x106 uint64
+       x106, x105 = bits.Mul64(x99, 0x5812631a5cf5d3ed)
+       var x107 uint64
+       var x108 uint64
+       x107, x108 = bits.Add64(x106, x103, uint64(0x0))
+       var x110 uint64
+       _, x110 = bits.Add64(x91, x105, uint64(0x0))
+       var x111 uint64
+       var x112 uint64
+       x111, x112 = bits.Add64(x93, x107, uint64(fiatScalarUint1(x110)))
+       var x113 uint64
+       var x114 uint64
+       x113, x114 = bits.Add64(x95, (uint64(fiatScalarUint1(x108)) + x104), uint64(fiatScalarUint1(x112)))
+       var x115 uint64
+       var x116 uint64
+       x115, x116 = bits.Add64(x97, x101, uint64(fiatScalarUint1(x114)))
+       var x117 uint64
+       var x118 uint64
+       x118, x117 = bits.Mul64(x3, 0x399411b7c309a3d)
+       var x119 uint64
+       var x120 uint64
+       x120, x119 = bits.Mul64(x3, 0xceec73d217f5be65)
+       var x121 uint64
+       var x122 uint64
+       x122, x121 = bits.Mul64(x3, 0xd00e1ba768859347)
+       var x123 uint64
+       var x124 uint64
+       x124, x123 = bits.Mul64(x3, 0xa40611e3449c0f01)
+       var x125 uint64
+       var x126 uint64
+       x125, x126 = bits.Add64(x124, x121, uint64(0x0))
+       var x127 uint64
+       var x128 uint64
+       x127, x128 = bits.Add64(x122, x119, uint64(fiatScalarUint1(x126)))
+       var x129 uint64
+       var x130 uint64
+       x129, x130 = bits.Add64(x120, x117, uint64(fiatScalarUint1(x128)))
+       var x131 uint64
+       var x132 uint64
+       x131, x132 = bits.Add64(x111, x123, uint64(0x0))
+       var x133 uint64
+       var x134 uint64
+       x133, x134 = bits.Add64(x113, x125, uint64(fiatScalarUint1(x132)))
+       var x135 uint64
+       var x136 uint64
+       x135, x136 = bits.Add64(x115, x127, uint64(fiatScalarUint1(x134)))
+       var x137 uint64
+       var x138 uint64
+       x137, x138 = bits.Add64(((uint64(fiatScalarUint1(x116)) + (uint64(fiatScalarUint1(x98)) + (uint64(fiatScalarUint1(x90)) + x78))) + x102), x129, uint64(fiatScalarUint1(x136)))
+       var x139 uint64
+       _, x139 = bits.Mul64(x131, 0xd2b51da312547e1b)
+       var x141 uint64
+       var x142 uint64
+       x142, x141 = bits.Mul64(x139, 0x1000000000000000)
+       var x143 uint64
+       var x144 uint64
+       x144, x143 = bits.Mul64(x139, 0x14def9dea2f79cd6)
+       var x145 uint64
+       var x146 uint64
+       x146, x145 = bits.Mul64(x139, 0x5812631a5cf5d3ed)
+       var x147 uint64
+       var x148 uint64
+       x147, x148 = bits.Add64(x146, x143, uint64(0x0))
+       var x150 uint64
+       _, x150 = bits.Add64(x131, x145, uint64(0x0))
+       var x151 uint64
+       var x152 uint64
+       x151, x152 = bits.Add64(x133, x147, uint64(fiatScalarUint1(x150)))
+       var x153 uint64
+       var x154 uint64
+       x153, x154 = bits.Add64(x135, (uint64(fiatScalarUint1(x148)) + x144), uint64(fiatScalarUint1(x152)))
+       var x155 uint64
+       var x156 uint64
+       x155, x156 = bits.Add64(x137, x141, uint64(fiatScalarUint1(x154)))
+       x157 := ((uint64(fiatScalarUint1(x156)) + (uint64(fiatScalarUint1(x138)) + (uint64(fiatScalarUint1(x130)) + x118))) + x142)
+       var x158 uint64
+       var x159 uint64
+       x158, x159 = bits.Sub64(x151, 0x5812631a5cf5d3ed, uint64(0x0))
+       var x160 uint64
+       var x161 uint64
+       x160, x161 = bits.Sub64(x153, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x159)))
+       var x162 uint64
+       var x163 uint64
+       x162, x163 = bits.Sub64(x155, uint64(0x0), uint64(fiatScalarUint1(x161)))
+       var x164 uint64
+       var x165 uint64
+       x164, x165 = bits.Sub64(x157, 0x1000000000000000, uint64(fiatScalarUint1(x163)))
+       var x167 uint64
+       _, x167 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x165)))
+       var x168 uint64
+       fiatScalarCmovznzU64(&x168, fiatScalarUint1(x167), x158, x151)
+       var x169 uint64
+       fiatScalarCmovznzU64(&x169, fiatScalarUint1(x167), x160, x153)
+       var x170 uint64
+       fiatScalarCmovznzU64(&x170, fiatScalarUint1(x167), x162, x155)
+       var x171 uint64
+       fiatScalarCmovznzU64(&x171, fiatScalarUint1(x167), x164, x157)
+       out1[0] = x168
+       out1[1] = x169
+       out1[2] = x170
+       out1[3] = x171
+}
+
+// fiatScalarToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+//     0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+//     out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
+//
+// Input Bounds:
+//
+//     arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]]
+//
+// Output Bounds:
+//
+//     out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]]
+func fiatScalarToBytes(out1 *[32]uint8, arg1 *[4]uint64) {
+       x1 := arg1[3]
+       x2 := arg1[2]
+       x3 := arg1[1]
+       x4 := arg1[0]
+       x5 := (uint8(x4) & 0xff)
+       x6 := (x4 >> 8)
+       x7 := (uint8(x6) & 0xff)
+       x8 := (x6 >> 8)
+       x9 := (uint8(x8) & 0xff)
+       x10 := (x8 >> 8)
+       x11 := (uint8(x10) & 0xff)
+       x12 := (x10 >> 8)
+       x13 := (uint8(x12) & 0xff)
+       x14 := (x12 >> 8)
+       x15 := (uint8(x14) & 0xff)
+       x16 := (x14 >> 8)
+       x17 := (uint8(x16) & 0xff)
+       x18 := uint8((x16 >> 8))
+       x19 := (uint8(x3) & 0xff)
+       x20 := (x3 >> 8)
+       x21 := (uint8(x20) & 0xff)
+       x22 := (x20 >> 8)
+       x23 := (uint8(x22) & 0xff)
+       x24 := (x22 >> 8)
+       x25 := (uint8(x24) & 0xff)
+       x26 := (x24 >> 8)
+       x27 := (uint8(x26) & 0xff)
+       x28 := (x26 >> 8)
+       x29 := (uint8(x28) & 0xff)
+       x30 := (x28 >> 8)
+       x31 := (uint8(x30) & 0xff)
+       x32 := uint8((x30 >> 8))
+       x33 := (uint8(x2) & 0xff)
+       x34 := (x2 >> 8)
+       x35 := (uint8(x34) & 0xff)
+       x36 := (x34 >> 8)
+       x37 := (uint8(x36) & 0xff)
+       x38 := (x36 >> 8)
+       x39 := (uint8(x38) & 0xff)
+       x40 := (x38 >> 8)
+       x41 := (uint8(x40) & 0xff)
+       x42 := (x40 >> 8)
+       x43 := (uint8(x42) & 0xff)
+       x44 := (x42 >> 8)
+       x45 := (uint8(x44) & 0xff)
+       x46 := uint8((x44 >> 8))
+       x47 := (uint8(x1) & 0xff)
+       x48 := (x1 >> 8)
+       x49 := (uint8(x48) & 0xff)
+       x50 := (x48 >> 8)
+       x51 := (uint8(x50) & 0xff)
+       x52 := (x50 >> 8)
+       x53 := (uint8(x52) & 0xff)
+       x54 := (x52 >> 8)
+       x55 := (uint8(x54) & 0xff)
+       x56 := (x54 >> 8)
+       x57 := (uint8(x56) & 0xff)
+       x58 := (x56 >> 8)
+       x59 := (uint8(x58) & 0xff)
+       x60 := uint8((x58 >> 8))
+       out1[0] = x5
+       out1[1] = x7
+       out1[2] = x9
+       out1[3] = x11
+       out1[4] = x13
+       out1[5] = x15
+       out1[6] = x17
+       out1[7] = x18
+       out1[8] = x19
+       out1[9] = x21
+       out1[10] = x23
+       out1[11] = x25
+       out1[12] = x27
+       out1[13] = x29
+       out1[14] = x31
+       out1[15] = x32
+       out1[16] = x33
+       out1[17] = x35
+       out1[18] = x37
+       out1[19] = x39
+       out1[20] = x41
+       out1[21] = x43
+       out1[22] = x45
+       out1[23] = x46
+       out1[24] = x47
+       out1[25] = x49
+       out1[26] = x51
+       out1[27] = x53
+       out1[28] = x55
+       out1[29] = x57
+       out1[30] = x59
+       out1[31] = x60
+}
+
+// fiatScalarFromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+//     0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+//     eval out1 mod m = bytes_eval arg1 mod m
+//     0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+//     arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]]
+//
+// Output Bounds:
+//
+//     out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]]
+func fiatScalarFromBytes(out1 *[4]uint64, arg1 *[32]uint8) {
+       x1 := (uint64(arg1[31]) << 56)
+       x2 := (uint64(arg1[30]) << 48)
+       x3 := (uint64(arg1[29]) << 40)
+       x4 := (uint64(arg1[28]) << 32)
+       x5 := (uint64(arg1[27]) << 24)
+       x6 := (uint64(arg1[26]) << 16)
+       x7 := (uint64(arg1[25]) << 8)
+       x8 := arg1[24]
+       x9 := (uint64(arg1[23]) << 56)
+       x10 := (uint64(arg1[22]) << 48)
+       x11 := (uint64(arg1[21]) << 40)
+       x12 := (uint64(arg1[20]) << 32)
+       x13 := (uint64(arg1[19]) << 24)
+       x14 := (uint64(arg1[18]) << 16)
+       x15 := (uint64(arg1[17]) << 8)
+       x16 := arg1[16]
+       x17 := (uint64(arg1[15]) << 56)
+       x18 := (uint64(arg1[14]) << 48)
+       x19 := (uint64(arg1[13]) << 40)
+       x20 := (uint64(arg1[12]) << 32)
+       x21 := (uint64(arg1[11]) << 24)
+       x22 := (uint64(arg1[10]) << 16)
+       x23 := (uint64(arg1[9]) << 8)
+       x24 := arg1[8]
+       x25 := (uint64(arg1[7]) << 56)
+       x26 := (uint64(arg1[6]) << 48)
+       x27 := (uint64(arg1[5]) << 40)
+       x28 := (uint64(arg1[4]) << 32)
+       x29 := (uint64(arg1[3]) << 24)
+       x30 := (uint64(arg1[2]) << 16)
+       x31 := (uint64(arg1[1]) << 8)
+       x32 := arg1[0]
+       x33 := (x31 + uint64(x32))
+       x34 := (x30 + x33)
+       x35 := (x29 + x34)
+       x36 := (x28 + x35)
+       x37 := (x27 + x36)
+       x38 := (x26 + x37)
+       x39 := (x25 + x38)
+       x40 := (x23 + uint64(x24))
+       x41 := (x22 + x40)
+       x42 := (x21 + x41)
+       x43 := (x20 + x42)
+       x44 := (x19 + x43)
+       x45 := (x18 + x44)
+       x46 := (x17 + x45)
+       x47 := (x15 + uint64(x16))
+       x48 := (x14 + x47)
+       x49 := (x13 + x48)
+       x50 := (x12 + x49)
+       x51 := (x11 + x50)
+       x52 := (x10 + x51)
+       x53 := (x9 + x52)
+       x54 := (x7 + uint64(x8))
+       x55 := (x6 + x54)
+       x56 := (x5 + x55)
+       x57 := (x4 + x56)
+       x58 := (x3 + x57)
+       x59 := (x2 + x58)
+       x60 := (x1 + x59)
+       out1[0] = x39
+       out1[1] = x46
+       out1[2] = x53
+       out1[3] = x60
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/scalarmult.go b/go/cm/sign/ed25519-blake2b/edwards25519/scalarmult.go
new file mode 100644 (file)
index 0000000..55c3f0e
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import "sync"
+
+// basepointTable is a set of 32 affineLookupTables, where table i is generated
+// from 256i * basepoint. It is precomputed the first time it's used.
+func basepointTable() *[32]affineLookupTable {
+       basepointTablePrecomp.initOnce.Do(func() {
+               p := NewGeneratorPoint()
+               for i := 0; i < 32; i++ {
+                       basepointTablePrecomp.table[i].FromP3(p)
+                       for j := 0; j < 8; j++ {
+                               p.Add(p, p)
+                       }
+               }
+       })
+       return &basepointTablePrecomp.table
+}
+
+var basepointTablePrecomp struct {
+       table    [32]affineLookupTable
+       initOnce sync.Once
+}
+
+// ScalarBaseMult sets v = x * B, where B is the canonical generator, and
+// returns v.
+//
+// The scalar multiplication is done in constant time.
+func (v *Point) ScalarBaseMult(x *Scalar) *Point {
+       basepointTable := basepointTable()
+
+       // Write x = sum(x_i * 16^i) so  x*B = sum( B*x_i*16^i )
+       // as described in the Ed25519 paper
+       //
+       // Group even and odd coefficients
+       // x*B     = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
+       //         + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
+       // x*B     = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
+       //    + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
+       //
+       // We use a lookup table for each i to get x_i*16^(2*i)*B
+       // and do four doublings to multiply by 16.
+       digits := x.signedRadix16()
+
+       multiple := &affineCached{}
+       tmp1 := &projP1xP1{}
+       tmp2 := &projP2{}
+
+       // Accumulate the odd components first
+       v.Set(NewIdentityPoint())
+       for i := 1; i < 64; i += 2 {
+               basepointTable[i/2].SelectInto(multiple, digits[i])
+               tmp1.AddAffine(v, multiple)
+               v.fromP1xP1(tmp1)
+       }
+
+       // Multiply by 16
+       tmp2.FromP3(v)       // tmp2 =    v in P2 coords
+       tmp1.Double(tmp2)    // tmp1 =  2*v in P1xP1 coords
+       tmp2.FromP1xP1(tmp1) // tmp2 =  2*v in P2 coords
+       tmp1.Double(tmp2)    // tmp1 =  4*v in P1xP1 coords
+       tmp2.FromP1xP1(tmp1) // tmp2 =  4*v in P2 coords
+       tmp1.Double(tmp2)    // tmp1 =  8*v in P1xP1 coords
+       tmp2.FromP1xP1(tmp1) // tmp2 =  8*v in P2 coords
+       tmp1.Double(tmp2)    // tmp1 = 16*v in P1xP1 coords
+       v.fromP1xP1(tmp1)    // now v = 16*(odd components)
+
+       // Accumulate the even components
+       for i := 0; i < 64; i += 2 {
+               basepointTable[i/2].SelectInto(multiple, digits[i])
+               tmp1.AddAffine(v, multiple)
+               v.fromP1xP1(tmp1)
+       }
+
+       return v
+}
+
+// ScalarMult sets v = x * q, and returns v.
+//
+// The scalar multiplication is done in constant time.
+func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
+       checkInitialized(q)
+
+       var table projLookupTable
+       table.FromP3(q)
+
+       // Write x = sum(x_i * 16^i)
+       // so  x*Q = sum( Q*x_i*16^i )
+       //         = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
+       //           <------compute inside out---------
+       //
+       // We use the lookup table to get the x_i*Q values
+       // and do four doublings to compute 16*Q
+       digits := x.signedRadix16()
+
+       // Unwrap first loop iteration to save computing 16*identity
+       multiple := &projCached{}
+       tmp1 := &projP1xP1{}
+       tmp2 := &projP2{}
+       table.SelectInto(multiple, digits[63])
+
+       v.Set(NewIdentityPoint())
+       tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
+       for i := 62; i >= 0; i-- {
+               tmp2.FromP1xP1(tmp1) // tmp2 =    (prev) in P2 coords
+               tmp1.Double(tmp2)    // tmp1 =  2*(prev) in P1xP1 coords
+               tmp2.FromP1xP1(tmp1) // tmp2 =  2*(prev) in P2 coords
+               tmp1.Double(tmp2)    // tmp1 =  4*(prev) in P1xP1 coords
+               tmp2.FromP1xP1(tmp1) // tmp2 =  4*(prev) in P2 coords
+               tmp1.Double(tmp2)    // tmp1 =  8*(prev) in P1xP1 coords
+               tmp2.FromP1xP1(tmp1) // tmp2 =  8*(prev) in P2 coords
+               tmp1.Double(tmp2)    // tmp1 = 16*(prev) in P1xP1 coords
+               v.fromP1xP1(tmp1)    //    v = 16*(prev) in P3 coords
+               table.SelectInto(multiple, digits[i])
+               tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
+       }
+       v.fromP1xP1(tmp1)
+       return v
+}
+
+// basepointNafTable is the nafLookupTable8 for the basepoint.
+// It is precomputed the first time it's used.
+func basepointNafTable() *nafLookupTable8 {
+       basepointNafTablePrecomp.initOnce.Do(func() {
+               basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
+       })
+       return &basepointNafTablePrecomp.table
+}
+
+var basepointNafTablePrecomp struct {
+       table    nafLookupTable8
+       initOnce sync.Once
+}
+
+// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
+// generator, and returns v.
+//
+// Execution time depends on the inputs.
+func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
+       checkInitialized(A)
+
+       // Similarly to the single variable-base approach, we compute
+       // digits and use them with a lookup table.  However, because
+       // we are allowed to do variable-time operations, we don't
+       // need constant-time lookups or constant-time digit
+       // computations.
+       //
+       // So we use a non-adjacent form of some width w instead of
+       // radix 16.  This is like a binary representation (one digit
+       // for each binary place) but we allow the digits to grow in
+       // magnitude up to 2^{w-1} so that the nonzero digits are as
+       // sparse as possible.  Intuitively, this "condenses" the
+       // "mass" of the scalar onto sparse coefficients (meaning
+       // fewer additions).
+
+       basepointNafTable := basepointNafTable()
+       var aTable nafLookupTable5
+       aTable.FromP3(A)
+       // Because the basepoint is fixed, we can use a wider NAF
+       // corresponding to a bigger table.
+       aNaf := a.nonAdjacentForm(5)
+       bNaf := b.nonAdjacentForm(8)
+
+       // Find the first nonzero coefficient.
+       i := 255
+       for j := i; j >= 0; j-- {
+               if aNaf[j] != 0 || bNaf[j] != 0 {
+                       break
+               }
+       }
+
+       multA := &projCached{}
+       multB := &affineCached{}
+       tmp1 := &projP1xP1{}
+       tmp2 := &projP2{}
+       tmp2.Zero()
+
+       // Move from high to low bits, doubling the accumulator
+       // at each iteration and checking whether there is a nonzero
+       // coefficient to look up a multiple of.
+       for ; i >= 0; i-- {
+               tmp1.Double(tmp2)
+
+               // Only update v if we have a nonzero coeff to add in.
+               if aNaf[i] > 0 {
+                       v.fromP1xP1(tmp1)
+                       aTable.SelectInto(multA, aNaf[i])
+                       tmp1.Add(v, multA)
+               } else if aNaf[i] < 0 {
+                       v.fromP1xP1(tmp1)
+                       aTable.SelectInto(multA, -aNaf[i])
+                       tmp1.Sub(v, multA)
+               }
+
+               if bNaf[i] > 0 {
+                       v.fromP1xP1(tmp1)
+                       basepointNafTable.SelectInto(multB, bNaf[i])
+                       tmp1.AddAffine(v, multB)
+               } else if bNaf[i] < 0 {
+                       v.fromP1xP1(tmp1)
+                       basepointNafTable.SelectInto(multB, -bNaf[i])
+                       tmp1.SubAffine(v, multB)
+               }
+
+               tmp2.FromP1xP1(tmp1)
+       }
+
+       v.fromP2(tmp2)
+       return v
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/constant_time.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/constant_time.go
new file mode 100644 (file)
index 0000000..563c1cf
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+// ConstantTimeCompare returns 1 if the two slices, x and y, have equal contents
+// and 0 otherwise. The time taken is a function of the length of the slices and
+// is independent of the contents. If the lengths of x and y do not match it
+// returns 0 immediately.
+func ConstantTimeCompare(x, y []byte) int {
+       if len(x) != len(y) {
+               return 0
+       }
+
+       var v byte
+
+       for i := 0; i < len(x); i++ {
+               v |= x[i] ^ y[i]
+       }
+
+       return ConstantTimeByteEq(v, 0)
+}
+
+// ConstantTimeSelect returns x if v == 1 and y if v == 0.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
+
+// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeByteEq(x, y uint8) int {
+       return int((uint32(x^y) - 1) >> 31)
+}
+
+// ConstantTimeEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeEq(x, y int32) int {
+       return int((uint64(uint32(x^y)) - 1) >> 63)
+}
+
+// ConstantTimeCopy copies the contents of y into x (a slice of equal length)
+// if v == 1. If v == 0, x is left unchanged. Its behavior is undefined if v
+// takes any other value.
+func ConstantTimeCopy(v int, x, y []byte) {
+       if len(x) != len(y) {
+               panic("subtle: slices have different lengths")
+       }
+
+       xmask := byte(v - 1)
+       ymask := byte(^(v - 1))
+       for i := 0; i < len(x); i++ {
+               x[i] = x[i]&xmask | y[i]&ymask
+       }
+}
+
+// ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
+// Its behavior is undefined if x or y are negative or > 2**31 - 1.
+func ConstantTimeLessOrEq(x, y int) int {
+       x32 := int32(x)
+       y32 := int32(y)
+       return int(((x32 - y32 - 1) >> 31) & 1)
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor.go
new file mode 100644 (file)
index 0000000..9090a3f
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+import "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/alias"
+
+// XORBytes sets dst[i] = x[i] ^ y[i] for all i < n = min(len(x), len(y)),
+// returning n, the number of bytes written to dst.
+//
+// If dst does not have length at least n,
+// XORBytes panics without writing anything to dst.
+//
+// dst and x or y may overlap exactly or not at all,
+// otherwise XORBytes may panic.
+func XORBytes(dst, x, y []byte) int {
+       n := min(len(x), len(y))
+       if n == 0 {
+               return 0
+       }
+       if n > len(dst) {
+               panic("subtle.XORBytes: dst too short")
+       }
+       if alias.InexactOverlap(dst[:n], x[:n]) || alias.InexactOverlap(dst[:n], y[:n]) {
+               panic("subtle.XORBytes: invalid overlap")
+       }
+       xorBytes(&dst[0], &x[0], &y[0], n) // arch-specific
+       return n
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_amd64.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_amd64.go
new file mode 100644 (file)
index 0000000..314ebaf
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_amd64.s b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_amd64.s
new file mode 100644 (file)
index 0000000..bcd93f4
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT, $0
+       MOVQ  dst+0(FP), BX
+       MOVQ  a+8(FP), SI
+       MOVQ  b+16(FP), CX
+       MOVQ  n+24(FP), DX
+       TESTQ $15, DX            // AND 15 & len, if not zero jump to not_aligned.
+       JNZ   not_aligned
+
+aligned:
+       MOVQ $0, AX // position in slices
+
+       PCALIGN $16
+loop16b:
+       MOVOU (SI)(AX*1), X0   // XOR 16byte forwards.
+       MOVOU (CX)(AX*1), X1
+       PXOR  X1, X0
+       MOVOU X0, (BX)(AX*1)
+       ADDQ  $16, AX
+       CMPQ  DX, AX
+       JNE   loop16b
+       RET
+
+       PCALIGN $16
+loop_1b:
+       SUBQ  $1, DX           // XOR 1byte backwards.
+       MOVB  (SI)(DX*1), DI
+       MOVB  (CX)(DX*1), AX
+       XORB  AX, DI
+       MOVB  DI, (BX)(DX*1)
+       TESTQ $7, DX           // AND 7 & len, if not zero jump to loop_1b.
+       JNZ   loop_1b
+       CMPQ  DX, $0           // if len is 0, ret.
+       JE    ret
+       TESTQ $15, DX          // AND 15 & len, if zero jump to aligned.
+       JZ    aligned
+
+not_aligned:
+       TESTQ $7, DX           // AND $7 & len, if not zero jump to loop_1b.
+       JNE   loop_1b
+       SUBQ  $8, DX           // XOR 8bytes backwards.
+       MOVQ  (SI)(DX*1), DI
+       MOVQ  (CX)(DX*1), AX
+       XORQ  AX, DI
+       MOVQ  DI, (BX)(DX*1)
+       CMPQ  DX, $16          // if len is greater or equal 16 here, it must be aligned.
+       JGE   aligned
+
+ret:
+       RET
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_arm64.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_arm64.go
new file mode 100644 (file)
index 0000000..78a928c
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_arm64.s b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_arm64.s
new file mode 100644 (file)
index 0000000..2864759
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT|NOFRAME, $0
+       MOVD    dst+0(FP), R0
+       MOVD    a+8(FP), R1
+       MOVD    b+16(FP), R2
+       MOVD    n+24(FP), R3
+       CMP     $64, R3
+       BLT     tail
+loop_64:
+       VLD1.P  64(R1), [V0.B16, V1.B16, V2.B16, V3.B16]
+       VLD1.P  64(R2), [V4.B16, V5.B16, V6.B16, V7.B16]
+       VEOR    V0.B16, V4.B16, V4.B16
+       VEOR    V1.B16, V5.B16, V5.B16
+       VEOR    V2.B16, V6.B16, V6.B16
+       VEOR    V3.B16, V7.B16, V7.B16
+       VST1.P  [V4.B16, V5.B16, V6.B16, V7.B16], 64(R0)
+       SUBS    $64, R3
+       CMP     $64, R3
+       BGE     loop_64
+tail:
+       // quick end
+       CBZ     R3, end
+       TBZ     $5, R3, less_than32
+       VLD1.P  32(R1), [V0.B16, V1.B16]
+       VLD1.P  32(R2), [V2.B16, V3.B16]
+       VEOR    V0.B16, V2.B16, V2.B16
+       VEOR    V1.B16, V3.B16, V3.B16
+       VST1.P  [V2.B16, V3.B16], 32(R0)
+less_than32:
+       TBZ     $4, R3, less_than16
+       LDP.P   16(R1), (R11, R12)
+       LDP.P   16(R2), (R13, R14)
+       EOR     R11, R13, R13
+       EOR     R12, R14, R14
+       STP.P   (R13, R14), 16(R0)
+less_than16:
+       TBZ     $3, R3, less_than8
+       MOVD.P  8(R1), R11
+       MOVD.P  8(R2), R12
+       EOR     R11, R12, R12
+       MOVD.P  R12, 8(R0)
+less_than8:
+       TBZ     $2, R3, less_than4
+       MOVWU.P 4(R1), R13
+       MOVWU.P 4(R2), R14
+       EORW    R13, R14, R14
+       MOVWU.P R14, 4(R0)
+less_than4:
+       TBZ     $1, R3, less_than2
+       MOVHU.P 2(R1), R15
+       MOVHU.P 2(R2), R16
+       EORW    R15, R16, R16
+       MOVHU.P R16, 2(R0)
+less_than2:
+       TBZ     $0, R3, end
+       MOVBU   (R1), R17
+       MOVBU   (R2), R19
+       EORW    R17, R19, R19
+       MOVBU   R19, (R0)
+end:
+       RET
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_generic.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_generic.go
new file mode 100644 (file)
index 0000000..0a5ed8a
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (!amd64 && !arm64 && !loong64 && !ppc64 && !ppc64le) || purego
+
+package subtle
+
+import (
+       "runtime"
+       "unsafe"
+)
+
+const wordSize = unsafe.Sizeof(uintptr(0))
+
+const supportsUnaligned = runtime.GOARCH == "386" ||
+       runtime.GOARCH == "amd64" ||
+       runtime.GOARCH == "ppc64" ||
+       runtime.GOARCH == "ppc64le" ||
+       runtime.GOARCH == "s390x"
+
+func xorBytes(dstb, xb, yb *byte, n int) {
+       // xorBytes assembly is written using pointers and n. Back to slices.
+       dst := unsafe.Slice(dstb, n)
+       x := unsafe.Slice(xb, n)
+       y := unsafe.Slice(yb, n)
+
+       if supportsUnaligned || aligned(dstb, xb, yb) {
+               xorLoop(words(dst), words(x), words(y))
+               if uintptr(n)%wordSize == 0 {
+                       return
+               }
+               done := n &^ int(wordSize-1)
+               dst = dst[done:]
+               x = x[done:]
+               y = y[done:]
+       }
+       xorLoop(dst, x, y)
+}
+
+// aligned reports whether dst, x, and y are all word-aligned pointers.
+func aligned(dst, x, y *byte) bool {
+       return (uintptr(unsafe.Pointer(dst))|uintptr(unsafe.Pointer(x))|uintptr(unsafe.Pointer(y)))&(wordSize-1) == 0
+}
+
+// words returns a []uintptr pointing at the same data as x,
+// with any trailing partial word removed.
+func words(x []byte) []uintptr {
+       n := uintptr(len(x)) / wordSize
+       if n == 0 {
+               // Avoid creating a *uintptr that refers to data smaller than a uintptr;
+               // see issue 59334.
+               return nil
+       }
+       return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), n)
+}
+
+func xorLoop[T byte | uintptr](dst, x, y []T) {
+       x = x[:len(dst)] // remove bounds check in loop
+       y = y[:len(dst)] // remove bounds check in loop
+       for i := range dst {
+               dst[i] = x[i] ^ y[i]
+       }
+}
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_loong64.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_loong64.go
new file mode 100644 (file)
index 0000000..f9d629d
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_loong64.s b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_loong64.s
new file mode 100644 (file)
index 0000000..83ed000
--- /dev/null
@@ -0,0 +1,166 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT, $0
+       MOVV    dst+0(FP), R4
+       MOVV    a+8(FP), R5
+       MOVV    b+16(FP), R6
+       MOVV    n+24(FP), R7
+
+       MOVV    $64, R9
+       BGEU    R7, R9, loop64  // n >= 64
+tail:
+       SRLV    $1, R9
+       BGEU    R7, R9, xor_32  // n >= 32 && n < 64
+       SRLV    $1, R9
+       BGEU    R7, R9, xor_16  // n >= 16 && n < 32
+       SRLV    $1, R9
+       BGEU    R7, R9, xor_8   // n >= 8 && n < 16
+       SRLV    $1, R9
+       BGEU    R7, R9, xor_4   // n >= 4 && n < 8
+       SRLV    $1, R9
+       BGEU    R7, R9, xor_2   // n >= 2 && n < 4
+       SRLV    $1, R9
+       BGEU    R7, R9, xor_1   // n = 1
+
+loop64:
+       MOVV    (R5), R10
+       MOVV    8(R5), R11
+       MOVV    16(R5), R12
+       MOVV    24(R5), R13
+       MOVV    (R6), R14
+       MOVV    8(R6), R15
+       MOVV    16(R6), R16
+       MOVV    24(R6), R17
+       XOR     R10, R14
+       XOR     R11, R15
+       XOR     R12, R16
+       XOR     R13, R17
+       MOVV    R14, (R4)
+       MOVV    R15, 8(R4)
+       MOVV    R16, 16(R4)
+       MOVV    R17, 24(R4)
+       MOVV    32(R5), R10
+       MOVV    40(R5), R11
+       MOVV    48(R5), R12
+       MOVV    56(R5), R13
+       MOVV    32(R6), R14
+       MOVV    40(R6), R15
+       MOVV    48(R6), R16
+       MOVV    56(R6), R17
+       XOR     R10, R14
+       XOR     R11, R15
+       XOR     R12, R16
+       XOR     R13, R17
+       MOVV    R14, 32(R4)
+       MOVV    R15, 40(R4)
+       MOVV    R16, 48(R4)
+       MOVV    R17, 56(R4)
+       ADDV    $64, R5
+       ADDV    $64, R6
+       ADDV    $64, R4
+       SUBV    $64, R7
+       // 64 in R9
+       BGEU    R7, R9, loop64
+       BEQ     R7, R0, end
+
+xor_32_check:
+       SRLV    $1, R9
+       BLT     R7, R9, xor_16_check
+xor_32:
+       MOVV    (R5), R10
+       MOVV    8(R5), R11
+       MOVV    16(R5), R12
+       MOVV    24(R5), R13
+       MOVV    (R6), R14
+       MOVV    8(R6), R15
+       MOVV    16(R6), R16
+       MOVV    24(R6), R17
+       XOR     R10, R14
+       XOR     R11, R15
+       XOR     R12, R16
+       XOR     R13, R17
+       MOVV    R14, (R4)
+       MOVV    R15, 8(R4)
+       MOVV    R16, 16(R4)
+       MOVV    R17, 24(R4)
+       ADDV    $32, R5
+       ADDV    $32, R6
+       ADDV    $32, R4
+       SUBV    $32, R7
+       BEQ     R7, R0, end
+
+xor_16_check:
+       SRLV    $1, R9
+       BLT     R7, R9, xor_8_check
+xor_16:
+       MOVV    (R5), R10
+       MOVV    8(R5), R11
+       MOVV    (R6), R12
+       MOVV    8(R6), R13
+       XOR     R10, R12
+       XOR     R11, R13
+       MOVV    R12, (R4)
+       MOVV    R13, 8(R4)
+       ADDV    $16, R5
+       ADDV    $16, R6
+       ADDV    $16, R4
+       SUBV    $16, R7
+       BEQ     R7, R0, end
+
+xor_8_check:
+       SRLV    $1, R9
+       BLT     R7, R9, xor_4_check
+xor_8:
+       MOVV    (R5), R10
+       MOVV    (R6), R11
+       XOR     R10, R11
+       MOVV    R11, (R4)
+       ADDV    $8, R5
+       ADDV    $8, R6
+       ADDV    $8, R4
+       SUBV    $8, R7
+       BEQ     R7, R0, end
+
+xor_4_check:
+       SRLV    $1, R9
+       BLT     R7, R9, xor_2_check
+xor_4:
+       MOVW    (R5), R10
+       MOVW    (R6), R11
+       XOR     R10, R11
+       MOVW    R11, (R4)
+       ADDV    $4, R5
+       ADDV    $4, R6
+       ADDV    $4, R4
+       SUBV    $4, R7
+       BEQ     R7, R0, end
+
+xor_2_check:
+       SRLV    $1, R9
+       BLT     R7, R9, xor_1
+xor_2:
+       MOVH    (R5), R10
+       MOVH    (R6), R11
+       XOR     R10, R11
+       MOVH    R11, (R4)
+       ADDV    $2, R5
+       ADDV    $2, R6
+       ADDV    $2, R4
+       SUBV    $2, R7
+       BEQ     R7, R0, end
+
+xor_1:
+       MOVB    (R5), R10
+       MOVB    (R6), R11
+       XOR     R10, R11
+       MOVB    R11, (R4)
+
+end:
+       RET
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_ppc64x.go b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_ppc64x.go
new file mode 100644 (file)
index 0000000..2d8d355
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (ppc64 || ppc64le) && !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_ppc64x.s b/go/cm/sign/ed25519-blake2b/edwards25519/subtle/xor_ppc64x.s
new file mode 100644 (file)
index 0000000..d54bc8b
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (ppc64 || ppc64le) && !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT, $0
+       MOVD    dst+0(FP), R3   // R3 = dst
+       MOVD    a+8(FP), R4     // R4 = a
+       MOVD    b+16(FP), R5    // R5 = b
+       MOVD    n+24(FP), R6    // R6 = n
+
+       CMPU    R6, $64, CR7    // Check if n ≥ 64 bytes
+       MOVD    R0, R8          // R8 = index
+       CMPU    R6, $8, CR6     // Check if 8 ≤ n < 64 bytes
+       BLE     CR6, small      // <= 8
+       BLT     CR7, xor32      // Case for 32 ≤ n < 64 bytes
+
+       // Case for n ≥ 64 bytes
+preloop64:
+       SRD     $6, R6, R7      // Set up loop counter
+       MOVD    R7, CTR
+       MOVD    $16, R10
+       MOVD    $32, R14
+       MOVD    $48, R15
+       ANDCC   $63, R6, R9     // Check for tailing bytes for later
+       PCALIGN $16
+       // Case for >= 64 bytes
+       // Process 64 bytes per iteration
+       // Load 4 vectors of a and b
+       // XOR the corresponding vectors
+       // from a and b and store the result
+loop64:
+       LXVD2X  (R4)(R8), VS32
+       LXVD2X  (R4)(R10), VS34
+       LXVD2X  (R4)(R14), VS36
+       LXVD2X  (R4)(R15), VS38
+       LXVD2X  (R5)(R8), VS33
+       LXVD2X  (R5)(R10), VS35
+       LXVD2X  (R5)(R14), VS37
+       LXVD2X  (R5)(R15), VS39
+       XXLXOR  VS32, VS33, VS32
+       XXLXOR  VS34, VS35, VS34
+       XXLXOR  VS36, VS37, VS36
+       XXLXOR  VS38, VS39, VS38
+       STXVD2X VS32, (R3)(R8)
+       STXVD2X VS34, (R3)(R10)
+       STXVD2X VS36, (R3)(R14)
+       STXVD2X VS38, (R3)(R15)
+       ADD     $64, R8
+       ADD     $64, R10
+       ADD     $64, R14
+       ADD     $64, R15
+       BDNZ    loop64
+       BC      12,2,LR         // BEQLR
+       MOVD    R9, R6
+       CMP     R6, $8
+       BLE     small
+       // Case for 8 <= n < 64 bytes
+       // Process 32 bytes if available
+xor32:
+       CMP     R6, $32
+       BLT     xor16
+       ADD     $16, R8, R9
+       LXVD2X  (R4)(R8), VS32
+       LXVD2X  (R4)(R9), VS33
+       LXVD2X  (R5)(R8), VS34
+       LXVD2X  (R5)(R9), VS35
+       XXLXOR  VS32, VS34, VS32
+       XXLXOR  VS33, VS35, VS33
+       STXVD2X VS32, (R3)(R8)
+       STXVD2X VS33, (R3)(R9)
+       ADD     $32, R8
+       ADD     $-32, R6
+       CMP     R6, $8
+       BLE     small
+       // Case for 8 <= n < 32 bytes
+       // Process 16 bytes if available
+xor16:
+       CMP     R6, $16
+       BLT     xor8
+       LXVD2X  (R4)(R8), VS32
+       LXVD2X  (R5)(R8), VS33
+       XXLXOR  VS32, VS33, VS32
+       STXVD2X VS32, (R3)(R8)
+       ADD     $16, R8
+       ADD     $-16, R6
+small:
+       CMP     R6, $0
+       BC      12,2,LR         // BEQLR
+xor8:
+#ifdef GOPPC64_power10
+       SLD     $56,R6,R17
+       ADD     R4,R8,R18
+       ADD     R5,R8,R19
+       ADD     R3,R8,R20
+       LXVL    R18,R17,V0
+       LXVL    R19,R17,V1
+       VXOR    V0,V1,V1
+       STXVL   V1,R20,R17
+       RET
+#else
+       CMP     R6, $8
+       BLT     xor4
+       // Case for 8 ≤ n < 16 bytes
+       MOVD    (R4)(R8), R14   // R14 = a[i,...,i+7]
+       MOVD    (R5)(R8), R15   // R15 = b[i,...,i+7]
+       XOR     R14, R15, R16   // R16 = a[] ^ b[]
+       SUB     $8, R6          // n = n - 8
+       MOVD    R16, (R3)(R8)   // Store to dst
+       ADD     $8, R8
+xor4:
+       CMP     R6, $4
+       BLT     xor2
+       MOVWZ   (R4)(R8), R14
+       MOVWZ   (R5)(R8), R15
+       XOR     R14, R15, R16
+       MOVW    R16, (R3)(R8)
+       ADD     $4,R8
+       ADD     $-4,R6
+xor2:
+       CMP     R6, $2
+       BLT     xor1
+       MOVHZ   (R4)(R8), R14
+       MOVHZ   (R5)(R8), R15
+       XOR     R14, R15, R16
+       MOVH    R16, (R3)(R8)
+       ADD     $2,R8
+       ADD     $-2,R6
+xor1:
+       CMP     R6, $0
+       BC      12,2,LR         // BEQLR
+       MOVBZ   (R4)(R8), R14   // R14 = a[i]
+       MOVBZ   (R5)(R8), R15   // R15 = b[i]
+       XOR     R14, R15, R16   // R16 = a[i] ^ b[i]
+       MOVB    R16, (R3)(R8)   // Store to dst
+#endif
+done:
+       RET
diff --git a/go/cm/sign/ed25519-blake2b/edwards25519/tables.go b/go/cm/sign/ed25519-blake2b/edwards25519/tables.go
new file mode 100644 (file)
index 0000000..cdcc5d8
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/edwards25519/subtle"
+)
+
+// A dynamic lookup table for variable-base, constant-time scalar muls.
+type projLookupTable struct {
+       points [8]projCached
+}
+
+// A precomputed lookup table for fixed-base, constant-time scalar muls.
+type affineLookupTable struct {
+       points [8]affineCached
+}
+
+// A dynamic lookup table for variable-base, variable-time scalar muls.
+type nafLookupTable5 struct {
+       points [8]projCached
+}
+
+// A precomputed lookup table for fixed-base, variable-time scalar muls.
+type nafLookupTable8 struct {
+       points [64]affineCached
+}
+
+// Constructors.
+
+// Builds a lookup table at runtime. Fast.
+func (v *projLookupTable) FromP3(q *Point) {
+       // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
+       // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
+       v.points[0].FromP3(q)
+       tmpP3 := Point{}
+       tmpP1xP1 := projP1xP1{}
+       for i := 0; i < 7; i++ {
+               // Compute (i+1)*Q as Q + i*Q and convert to a projCached
+               // This is needlessly complicated because the API has explicit
+               // receivers instead of creating stack objects and relying on RVO
+               v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
+       }
+}
+
+// This is not optimised for speed; fixed-base tables should be precomputed.
+func (v *affineLookupTable) FromP3(q *Point) {
+       // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
+       // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
+       v.points[0].FromP3(q)
+       tmpP3 := Point{}
+       tmpP1xP1 := projP1xP1{}
+       for i := 0; i < 7; i++ {
+               // Compute (i+1)*Q as Q + i*Q and convert to affineCached
+               v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
+       }
+}
+
+// Builds a lookup table at runtime. Fast.
+func (v *nafLookupTable5) FromP3(q *Point) {
+       // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
+       // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
+       v.points[0].FromP3(q)
+       q2 := Point{}
+       q2.Add(q, q)
+       tmpP3 := Point{}
+       tmpP1xP1 := projP1xP1{}
+       for i := 0; i < 7; i++ {
+               v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
+       }
+}
+
+// This is not optimised for speed; fixed-base tables should be precomputed.
+func (v *nafLookupTable8) FromP3(q *Point) {
+       v.points[0].FromP3(q)
+       q2 := Point{}
+       q2.Add(q, q)
+       tmpP3 := Point{}
+       tmpP1xP1 := projP1xP1{}
+       for i := 0; i < 63; i++ {
+               v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
+       }
+}
+
+// Selectors.
+
+// Set dest to x*Q, where -8 <= x <= 8, in constant time.
+func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
+       // Compute xabs = |x|
+       xmask := x >> 7
+       xabs := uint8((x + xmask) ^ xmask)
+
+       dest.Zero()
+       for j := 1; j <= 8; j++ {
+               // Set dest = j*Q if |x| = j
+               cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
+               dest.Select(&v.points[j-1], dest, cond)
+       }
+       // Now dest = |x|*Q, conditionally negate to get x*Q
+       dest.CondNeg(int(xmask & 1))
+}
+
+// Set dest to x*Q, where -8 <= x <= 8, in constant time.
+func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
+       // Compute xabs = |x|
+       xmask := x >> 7
+       xabs := uint8((x + xmask) ^ xmask)
+
+       dest.Zero()
+       for j := 1; j <= 8; j++ {
+               // Set dest = j*Q if |x| = j
+               cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
+               dest.Select(&v.points[j-1], dest, cond)
+       }
+       // Now dest = |x|*Q, conditionally negate to get x*Q
+       dest.CondNeg(int(xmask & 1))
+}
+
+// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
+func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
+       *dest = v.points[x/2]
+}
+
+// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
+func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
+       *dest = v.points[x/2]
+}
similarity index 82%
rename from go/cm/ed25519-blake2b/kp.go
rename to go/cm/sign/ed25519-blake2b/kp.go
index 7ec5892d8650dcbee3708b30b6e1e691c9cef9005e3a7e16f951e43a9ce0b88d..e89b549d9157e86308d3539e631ceac744587a087ed631d5e52209babda1b148 100644 (file)
 package ed25519blake2b
 
 import (
-       "crypto/rand"
-
-       "go.cypherpunks.su/keks/cm/ed25519-blake2b/ed25519"
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/ed25519"
 )
 
 func NewKeypair() (signer *Signer, prv, pub []byte, err error) {
-       var prvEd ed25519.PrivateKey
-       var pubEd ed25519.PublicKey
-       pubEd, prvEd, err = ed25519.GenerateKey(rand.Reader)
+       var prvEd *ed25519.PrivateKey
+       prvEd, err = ed25519.GenerateKey()
        if err != nil {
                return
        }
        signer = &Signer{Prv: prvEd}
        prv = prvEd.Seed()
-       pub = pubEd[:]
+       pub = prvEd.PublicKey()
        return
 }
similarity index 70%
rename from go/cm/ed25519-blake2b/signer.go
rename to go/cm/sign/ed25519-blake2b/signer.go
index 28acbdf7535183cc0d87fee182ef84520d21501f8393e0a86aa3d2e702c42b1a..001ab451a995610821a1e0586176ef07d77f19f95431fbc601f0ebc85454dfe9 100644 (file)
@@ -22,25 +22,25 @@ import (
        "io"
        "runtime"
 
-       "go.cypherpunks.su/keks/cm/ed25519-blake2b/ed25519"
+       cmblake2b "go.cypherpunks.su/keks/cm/hash/blake2b"
        "go.cypherpunks.su/keks/cm/hash/merkle"
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/ed25519"
+       "go.cypherpunks.su/keks/cm/sign/mode"
        "golang.org/x/crypto/blake2b"
-
-       "go.cypherpunks.su/keks/cm/sign"
 )
 
 type Signer struct {
-       Prv       ed25519.PrivateKey
-       mode      sign.Mode
+       Prv       *ed25519.PrivateKey
+       mode      mode.Mode
        prehasher *hash.Hash
 }
 
-func (s *Signer) SetMode(m sign.Mode) error {
+func (s *Signer) SetMode(m mode.Mode) error {
        switch m {
-       case sign.ModePure:
+       case mode.Pure:
                s.mode = m
                return nil
-       case sign.ModePrehash:
+       case mode.Prehash:
                s.mode = m
                h, err := blake2b.New512(nil)
                if err != nil {
@@ -48,9 +48,9 @@ func (s *Signer) SetMode(m sign.Mode) error {
                }
                s.prehasher = &h
                return nil
-       case sign.ModeMerkle:
+       case mode.Merkle:
                s.mode = m
-               h := NewMerkleHasher(merkle.DefaultChunkLen, runtime.NumCPU())
+               h := cmblake2b.NewMerkleHasher(merkle.DefaultChunkLen, runtime.NumCPU())
                s.prehasher = &h
                return nil
        default:
@@ -58,24 +58,24 @@ func (s *Signer) SetMode(m sign.Mode) error {
        }
 }
 
-func (s *Signer) Mode() sign.Mode {
+func (s *Signer) Mode() mode.Mode {
        return s.mode
 }
 
 func (s *Signer) Algo() string {
        switch s.mode {
-       case sign.ModePure:
+       case mode.Pure:
                return Ed25519BLAKE2b
-       case sign.ModePrehash:
+       case mode.Prehash:
                return Ed25519PhBLAKE2b
-       case sign.ModeMerkle:
+       case mode.Merkle:
                return Ed25519PhBLAKE2bMerkle
        }
        return ""
 }
 
 func (s *Signer) Public() crypto.PublicKey {
-       return s.Prv.Public()
+       return s.Prv.PublicKey()
 }
 
 func (s *Signer) Sign(
@@ -84,10 +84,10 @@ func (s *Signer) Sign(
        opts crypto.SignerOpts,
 ) (signature []byte, err error) {
        switch s.mode {
-       case sign.ModePure:
-               return s.Prv.Sign(rand, msg, opts)
-       case sign.ModePrehash, sign.ModeMerkle:
-               return s.Prv.Sign(rand, msg, &ed25519.Options{Hash: crypto.BLAKE2b_512})
+       case mode.Pure:
+               return ed25519.Sign(s.Prv, msg), nil
+       case mode.Prehash, mode.Merkle:
+               return ed25519.SignPH(s.Prv, msg, "")
        default:
                panic("unsupported mode")
        }
@@ -98,12 +98,16 @@ func (s *Signer) Prehasher() *hash.Hash {
 }
 
 func NewSigner(v []byte) (prv *Signer, pub []byte, err error) {
-       if len(v) != ed25519.SeedSize {
+       if len(v) != 32 {
                err = errors.New("wrong ed25519 private key size")
                return
        }
-       p := ed25519.NewKeyFromSeed(v)
-       pub = p[ed25519.SeedSize:]
+       var p *ed25519.PrivateKey
+       p, err = ed25519.NewPrivateKeyFromSeed(v)
+       if err != nil {
+               return
+       }
+       pub = p.PublicKey()
        prv = &Signer{Prv: p}
        return
 }
similarity index 69%
rename from go/cm/ed25519-blake2b/verify.go
rename to go/cm/sign/ed25519-blake2b/verify.go
index f80d5010a206c6208e6c6d2b3736eef027ac59c7e9de37f2ae67998000f0edfe..dfa4264ec40f0c008f7867ee5e49cd04b3ed17cfac22648e9c4c1855c8be0e83 100644 (file)
 package ed25519blake2b
 
 import (
-       "crypto"
        "errors"
 
-       "go.cypherpunks.su/keks/cm/ed25519-blake2b/ed25519"
+       "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b/ed25519"
 )
 
 func Verify(pub, signed, signature []byte) (valid bool, err error) {
-       if len(pub) != ed25519.PublicKeySize {
+       if len(pub) != 32 {
                err = errors.New("invalid ed25519 public key size")
                return
        }
-       valid = ed25519.Verify(ed25519.PublicKey(pub), signed, signature)
+       var pk *ed25519.PublicKey
+       pk, err = ed25519.NewPublicKey(pub)
+       if err != nil {
+               return
+       }
+       valid = ed25519.Verify(pk, signed, signature) == nil
        return
 }
 
 func VerifyPrehash(pub, hsh, signature []byte) (valid bool, err error) {
-       if len(pub) != ed25519.PublicKeySize {
+       if len(pub) != 32 {
                err = errors.New("invalid ed25519 public key size")
                return
        }
-       err = ed25519.VerifyWithOptions(
-               ed25519.PublicKey(pub),
-               hsh,
-               signature,
-               &ed25519.Options{Hash: crypto.BLAKE2b_512},
-       )
-       if err == nil {
-               valid = true
-       } else {
-               if err.Error() == "ed25519: invalid signature" {
-                       valid = false
-                       err = nil
-               }
+       var pk *ed25519.PublicKey
+       pk, err = ed25519.NewPublicKey(pub)
+       if err != nil {
+               return
        }
+       valid = ed25519.VerifyPH(pk, hsh, signature, "") == nil
        return
 }
similarity index 86%
rename from go/cm/gost/gost.go
rename to go/cm/sign/gost/gost.go
index 71487d2e1b2de0256d4700b763c2708142d9966a4d03a69ee7597da0a03c1e7e..8c67bd0ad0e965ab6a715a1a7307bdf95a6f48ea864487ae54ecec5a09ab4bab 100644 (file)
@@ -20,8 +20,10 @@ import (
 )
 
 const (
-       GOST3410256A = "gost3410-256A"
-       GOST3410512C = "gost3410-512C"
+       GOST3410256A       = "gost3410-256A"
+       GOST3410512C       = "gost3410-512C"
+       GOST3410256AMerkle = "gost3410-256A-merkle"
+       GOST3410512CMerkle = "gost3410-512C-merkle"
 )
 
 func CurveByName(name string) (curve *gost3410.Curve) {
similarity index 100%
rename from go/cm/gost/kp.go
rename to go/cm/sign/gost/kp.go
similarity index 86%
rename from go/cm/gost/signer.go
rename to go/cm/sign/gost/signer.go
index 785e2484da010a9d6484bd9d7339ffea5761d5d3dfe6e73bc6430366be4f64b5..99a3a3ecf998db4e5e69ccb6390de5d3eb7e2a985fc2362d53b9ef894022f970 100644 (file)
@@ -26,30 +26,31 @@ import (
        "go.cypherpunks.su/gogost/v6/gost34112012256"
        "go.cypherpunks.su/gogost/v6/gost34112012512"
 
+       hashgost "go.cypherpunks.su/keks/cm/hash/gost"
        "go.cypherpunks.su/keks/cm/hash/merkle"
-       "go.cypherpunks.su/keks/cm/sign"
+       "go.cypherpunks.su/keks/cm/sign/mode"
 )
 
 type Signer struct {
        NewHasher func() hash.Hash
        Prv       *gost3410.PrivateKey
        prehasher *hash.Hash
-       mode      sign.Mode
+       mode      mode.Mode
 }
 
-func (s *Signer) SetMode(m sign.Mode) error {
+func (s *Signer) SetMode(m mode.Mode) error {
        switch m {
-       case sign.ModePure:
+       case mode.Pure:
                s.mode = m
                return nil
-       case sign.ModePrehash:
+       case mode.Prehash:
                s.mode = m
                p := s.NewHasher()
                s.prehasher = &p
                return nil
-       case sign.ModeMerkle:
+       case mode.Merkle:
                s.mode = m
-               p := NewMerkleHasher(s.NewHasher, merkle.DefaultChunkLen, runtime.NumCPU())
+               p := hashgost.NewMerkleHasher(s.NewHasher, merkle.DefaultChunkLen, runtime.NumCPU())
                s.prehasher = &p
                return nil
        default:
@@ -57,7 +58,7 @@ func (s *Signer) SetMode(m sign.Mode) error {
        }
 }
 
-func (s *Signer) Mode() sign.Mode {
+func (s *Signer) Mode() mode.Mode {
        return s.mode
 }
 
@@ -68,12 +69,12 @@ func (s *Signer) Prehasher() *hash.Hash {
 func (s *Signer) Algo() string {
        switch s.Prv.C.PointSize() {
        case 32:
-               if s.mode == sign.ModeMerkle {
+               if s.mode == mode.Merkle {
                        return GOST3410256AMerkle
                }
                return GOST3410256A
        case 64:
-               if s.mode == sign.ModeMerkle {
+               if s.mode == mode.Merkle {
                        return GOST3410512CMerkle
                }
                return GOST3410512C
@@ -93,11 +94,11 @@ func (s *Signer) Sign(
 ) (signature []byte, err error) {
        var hsh []byte
        switch s.mode {
-       case sign.ModePure:
+       case mode.Pure:
                h := s.NewHasher()
                h.Write(msg)
                hsh = h.Sum(nil)
-       case sign.ModePrehash, sign.ModeMerkle:
+       case mode.Prehash, mode.Merkle:
                hsh = msg
        default:
                panic("unsupported mode")
similarity index 94%
rename from go/cm/gost/verify.go
rename to go/cm/sign/gost/verify.go
index f09ec74a1c4920fd88f54aa0e89789f063249bd2e12275725556d95b89402fe9..1ca490a0bcac51b833249f2ced7d4e06fd1da58aa2843f896d3187cc34efb791 100644 (file)
 package gost
 
 import (
+       "bytes"
        "hash"
+       "io"
 
        "go.cypherpunks.su/gogost/v6/gost3410"
        "go.cypherpunks.su/gogost/v6/gost34112012256"
        "go.cypherpunks.su/gogost/v6/gost34112012512"
-       "go.cypherpunks.su/keks/cm/utils"
 )
 
 func Verify(algo string, pub, signed, signature []byte) (valid bool, err error) {
@@ -37,7 +38,10 @@ func Verify(algo string, pub, signed, signature []byte) (valid bool, err error)
        case GOST3410512C:
                hasher = gost34112012512.New()
        }
-       utils.MustWrite(hasher, signed)
+       _, err = io.Copy(hasher, bytes.NewReader(signed))
+       if err != nil {
+               return
+       }
        hsh := hasher.Sum(nil)
        valid, err = pk.VerifyDigest(hsh,
                append(signature[len(signature)/2:], signature[:len(signature)/2]...))
index b8b5ca18ee2f09377f53346c4f9c96d2942eb022ee3e8b8dbb5b4ac24d094ccf..a641bd286eec83121de619f4cdb903485e28d6ff81c606492169d622b5c49b3e 100644 (file)
@@ -3,12 +3,14 @@ package sign
 import (
        "crypto"
        "hash"
+
+       "go.cypherpunks.su/keks/cm/sign/mode"
 )
 
 type Iface interface {
        crypto.Signer
-       SetMode(Mode) error
+       SetMode(mode.Mode) error
        Prehasher() *hash.Hash
        Algo() string
-       Mode() Mode
+       Mode() mode.Mode
 }
diff --git a/go/cm/sign/mode.go b/go/cm/sign/mode.go
deleted file mode 100644 (file)
index db6b94d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package sign
-
-type Mode int
-
-const (
-       ModePure    Mode = 0
-       ModePrehash      = iota
-       ModeMerkle       = iota
-
-       PrehashT = "prehash"
-)
diff --git a/go/cm/sign/mode/mode.go b/go/cm/sign/mode/mode.go
new file mode 100644 (file)
index 0000000..9c95af8
--- /dev/null
@@ -0,0 +1,11 @@
+package mode
+
+type Mode int
+
+const (
+       Pure    Mode = 0
+       Prehash      = iota
+       Merkle       = iota
+
+       PrehashT = "prehash"
+)
similarity index 80%
rename from go/cm/prv.go
rename to go/cm/sign/prv.go
index 64ca636e1c791b92d161a9e954f3d2a65551509d4c3cf5731ea3449388966db1..e18331c7059f716b09011babb9fa2314cec3fb40a0e306b7822967528edf9d1b 100644 (file)
 // You should have received a copy of the GNU Lesser General Public
 // License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package cm
+package sign
 
 import (
        "errors"
        "fmt"
 
        "go.cypherpunks.su/keks"
-       ed25519blake2b "go.cypherpunks.su/keks/cm/ed25519-blake2b"
-       "go.cypherpunks.su/keks/cm/gost"
-       "go.cypherpunks.su/keks/cm/sign"
+       "go.cypherpunks.su/keks/cm"
+       ed25519blake2b "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b"
+       "go.cypherpunks.su/keks/cm/sign/gost"
 )
 
+const PrvMagic = keks.Magic("cm/prv")
+
 // Parse private key contained in AV KEKS-encoded structure.
-func PrvParse(data []byte) (prv sign.Iface, pub []byte, err error) {
+func PrvParse(data []byte) (prv Iface, pub []byte, err error) {
        {
                var magic keks.Magic
                magic, data = keks.StripMagic(data)
@@ -36,7 +38,7 @@ func PrvParse(data []byte) (prv sign.Iface, pub []byte, err error) {
                }
        }
        d := keks.NewDecoderFromBytes(data, &keks.DecodeOpts{MaxStrLen: 1 << 16})
-       var av AV
+       var av cm.AV
        if err = d.DecodeStruct(&av); err != nil {
                return
        }
@@ -45,9 +47,9 @@ func PrvParse(data []byte) (prv sign.Iface, pub []byte, err error) {
                return
        }
        switch av.A {
-       case Ed25519BLAKE2b:
+       case ed25519blake2b.Ed25519BLAKE2b:
                prv, pub, err = ed25519blake2b.NewSigner(av.V)
-       case GOST3410256A, GOST3410512C:
+       case gost.GOST3410256A, gost.GOST3410512C:
                prv, pub, err = gost.NewSigner(av.V)
        default:
                err = fmt.Errorf("unknown private key algo: %s", av.A)
similarity index 93%
rename from go/cm/pub.go
rename to go/cm/sign/pub.go
index f2e11affdef7fcbfeda62518acdd7136fff34879489137a38922937e673e1983..4b8a89b78fcc5e220d66b07b112c2db4e8112ac9defb0157815b78faa1294706 100644 (file)
@@ -13,7 +13,7 @@
 // You should have received a copy of the GNU Lesser General Public
 // License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package cm
+package sign
 
 import (
        "bytes"
@@ -25,9 +25,8 @@ import (
        "github.com/google/uuid"
 
        "go.cypherpunks.su/keks"
-       ed25519blake2b "go.cypherpunks.su/keks/cm/ed25519-blake2b"
-       "go.cypherpunks.su/keks/cm/gost"
-       "go.cypherpunks.su/keks/cm/sign"
+       ed25519blake2b "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b"
+       "go.cypherpunks.su/keks/cm/sign/gost"
 )
 
 const (
@@ -150,7 +149,7 @@ func (pub *PubLoad) Can(ku string) (yes bool) {
 // generated UUIDv7. since and till times must not have nanoseconds part.
 func (signed *Signed) CertifyWith(
        parent *PubLoad,
-       prv sign.Iface,
+       prv Iface,
        since, till time.Time,
 ) error {
        exp := []time.Time{since, till}
@@ -171,15 +170,15 @@ func (pub *PubLoad) CheckSignature(algo string, signed, signature []byte) (err e
        key := pub.Pub[0]
        var valid bool
        switch key.A {
-       case Ed25519BLAKE2b:
-               if algo != Ed25519BLAKE2b {
+       case ed25519blake2b.Ed25519BLAKE2b:
+               if algo != ed25519blake2b.Ed25519BLAKE2b {
                        return ErrBadSigAlgo
                }
                valid, err = ed25519blake2b.Verify(key.V, signed, signature)
                if !valid {
                        err = ErrSigInvalid
                }
-       case GOST3410256A, GOST3410512C:
+       case gost.GOST3410256A, gost.GOST3410512C:
                if algo != key.A {
                        return ErrBadSigAlgo
                }
@@ -206,10 +205,10 @@ func (pub *PubLoad) CheckSignaturePrehash(
        key := pub.Pub[0]
        var valid bool
        switch key.A {
-       case Ed25519BLAKE2b:
+       case ed25519blake2b.Ed25519BLAKE2b:
                switch algo {
-               case Ed25519PhBLAKE2b:
-               case Ed25519PhBLAKE2bMerkle:
+               case ed25519blake2b.Ed25519PhBLAKE2b:
+               case ed25519blake2b.Ed25519PhBLAKE2bMerkle:
                default:
                        return ErrBadSigAlgo
                }
@@ -217,12 +216,12 @@ func (pub *PubLoad) CheckSignaturePrehash(
                if !valid {
                        err = ErrSigInvalid
                }
-       case GOST3410256A, GOST3410512C:
+       case gost.GOST3410256A, gost.GOST3410512C:
                switch algo {
-               case GOST3410256A:
-               case GOST3410256AMerkle:
-               case GOST3410512C:
-               case GOST3410512CMerkle:
+               case gost.GOST3410256A:
+               case gost.GOST3410256AMerkle:
+               case gost.GOST3410512C:
+               case gost.GOST3410512CMerkle:
                default:
                        return ErrBadSigAlgo
                }
similarity index 94%
rename from go/cm/signed.go
rename to go/cm/sign/signed.go
index 7a67fb6eec4ba0694b46401e7cd64ab670fda2d97860f77807f7b521d25ac48b..18dc57bd316d6754276bbe11b3bc595219e103fb7ecfbb954188c985eacd38ef 100644 (file)
@@ -13,7 +13,7 @@
 // You should have received a copy of the GNU Lesser General Public
 // License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package cm
+package sign
 
 import (
        "bytes"
@@ -25,7 +25,8 @@ import (
        "github.com/google/uuid"
 
        "go.cypherpunks.su/keks"
-       "go.cypherpunks.su/keks/cm/sign"
+       "go.cypherpunks.su/keks/cm"
+       "go.cypherpunks.su/keks/cm/sign/mode"
 )
 
 const SignedMagic = keks.Magic("cm/signed")
@@ -51,7 +52,7 @@ type SigTBS struct {
 type Sig struct {
        TBS    SigTBS    `keks:"tbs"`
        PubLoc *[]string `keks:"pub-loc,omitempty"`
-       Sign   AV        `keks:"sign"`
+       Sign   cm.AV     `keks:"sign"`
 }
 
 type Signed struct {
@@ -118,13 +119,13 @@ func SignedParse(data []byte) (*Signed, error) {
 // Sign Signed's contents and sigTBS corresponding data with the
 // provided prv signer, having parent certififer. Signature is appended
 // to the signed.Sigs. parent must have "sig" key-usage.
-func (signed *Signed) SignWith(parent *PubLoad, prv sign.Iface, sigTBS SigTBS) (err error) {
+func (signed *Signed) SignWith(parent *PubLoad, prv Iface, sigTBS SigTBS) (err error) {
        if !parent.Can(KUSig) || len(parent.Pub) != 1 {
                return errors.New("parent can not sign")
        }
        sigTBS.SID = parent.Pub[0].Id
        var tbs []byte
-       if prv.Mode() == sign.ModePure {
+       if prv.Mode() == mode.Pure {
                var b bytes.Buffer
                if _, err = keks.Encode(&b, signed.Load, nil); err != nil {
                        return
diff --git a/go/cm/sntrup4591761-x25519/go.mod b/go/cm/sntrup4591761-x25519/go.mod
deleted file mode 100644 (file)
index 4706ebb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-module go.cypherpunks.su/keks/cm/sntrup4591761-x25519
-
-go 1.24
-
-require github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a
diff --git a/go/cm/sntrup4591761-x25519/go.sum b/go/cm/sntrup4591761-x25519/go.sum
deleted file mode 100644 (file)
index 18a1c89..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a h1:clYxJ3Os0EQUKDDVU8M0oipllX0EkuFNBfhVQuIfyF0=
-github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a/go.mod h1:z/9Ck1EDixEbBbZ2KH2qNHekEmDLTOZ+FyoIPWWSVOI=
diff --git a/go/cm/utils/utils.go b/go/cm/utils/utils.go
deleted file mode 100644 (file)
index c4bec88..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// GoKEKS/CM -- KEKS-encoded cryptographic messages
-// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation, version 3 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-package utils
-
-import (
-       "fmt"
-       "io"
-       "os"
-)
-
-func MustWrite(w io.Writer, data []byte) {
-       n, err := w.Write(data)
-       if err != nil {
-               panic(err)
-       }
-       if n != len(data) {
-               panic("not full write")
-       }
-}
-
-func MustReadFile(p string) []byte {
-       data, err := os.ReadFile(p)
-       if err != nil {
-               panic(fmt.Errorf("read %s: %v", p, err))
-       }
-       return data
-}
index 540eec2ba9f1dd3aeadecbf4ade38db5d4cfcb86cda5d86c1d880be564f66a32..8240e2d8f0ed32e0c3cbc5dd2d5c4ad2f8484be9c2e408bc67995c2be8da133e 100644 (file)
--- a/go/go.mod
+++ b/go/go.mod
@@ -2,12 +2,11 @@ module go.cypherpunks.su/keks
 
 go 1.24
 
-require go.cypherpunks.su/tai64n/v4 v4.1.0
-
 require (
        github.com/google/uuid v1.6.0
        github.com/mitchellh/mapstructure v1.5.0
-       golang.org/x/term v0.27.0
+       go.cypherpunks.su/tai64n/v4 v4.1.0
+       golang.org/x/term v0.28.0
 )
 
-require golang.org/x/sys v0.28.0 // indirect
+require golang.org/x/sys v0.29.0 // indirect
index 6790579f6397a3031b924681d5bc13d7b277fdcc855d63d141821ec24630f805..268b767f0a6c374b4de4e0d48088443409edb37abf34ba22cdfcb288cab20234 100644 (file)
--- a/go/go.sum
+++ b/go/go.sum
@@ -4,7 +4,7 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 go.cypherpunks.su/tai64n/v4 v4.1.0 h1:jW0EyklKXpSy9DSFMcDbu7XuLlMkn6kkpNWiMG6UT5c=
 go.cypherpunks.su/tai64n/v4 v4.1.0/go.mod h1:/uKUdhLOy8UciRKpapPaFXSOoa/SiXjs3XsDDpAz7OA=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
-golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
+golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=