]> Sergey Matveev's repositories - vors.git/commitdiff
Post-quantum handshake authentication v5.0.0
authorSergey Matveev <stargrave@stargrave.org>
Wed, 16 Jul 2025 14:25:33 +0000 (17:25 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 2 Aug 2025 07:57:40 +0000 (10:57 +0300)
53 files changed:
cmd/client/audio.go
cmd/client/gui.go
cmd/client/main.go
cmd/client/stats.go
cmd/keygen/main.go
cmd/server/main.go
cmd/server/peer.go
cmd/server/room.go
cmd/vad/main.go
doc/Features
doc/INSTALL
doc/PQHS [new file with mode: 0644]
doc/Protocol
doc/Usage
doc/index
go.mod
go.sum
internal/incr.go [new file with mode: 0644]
internal/noise.go [deleted file]
internal/ns.go
internal/var.go
makedist
pqhs/client.go [new file with mode: 0644]
pqhs/const.go [new file with mode: 0644]
pqhs/dh.go [new file with mode: 0644]
pqhs/hs_test.go [new file with mode: 0644]
pqhs/key.go [new file with mode: 0644]
pqhs/mceliece6960119/README [new file with mode: 0644]
pqhs/mceliece6960119/benes.go [new file with mode: 0644]
pqhs/mceliece6960119/fft.go [new file with mode: 0644]
pqhs/mceliece6960119/internal/controlbits.go [new file with mode: 0644]
pqhs/mceliece6960119/internal/djbsort.go [new file with mode: 0644]
pqhs/mceliece6960119/internal/fft_const.go [new file with mode: 0644]
pqhs/mceliece6960119/internal/powers.go [new file with mode: 0644]
pqhs/mceliece6960119/math/gf2e12/gf4096.go [new file with mode: 0644]
pqhs/mceliece6960119/math/gf2e13/gf8192.go [new file with mode: 0644]
pqhs/mceliece6960119/mceliece.go [new file with mode: 0644]
pqhs/mceliece6960119/operations.go [new file with mode: 0644]
pqhs/mceliece6960119/pk_gen.go [new file with mode: 0644]
pqhs/mceliece6960119/vec.go [new file with mode: 0644]
pqhs/server.go [new file with mode: 0644]
pqhs/shake.go [new file with mode: 0644]
pqhs/sntrup761/README [new file with mode: 0644]
pqhs/sntrup761/kem/kem.go [new file with mode: 0644]
pqhs/sntrup761/kem/ntruprime/doc.go [new file with mode: 0644]
pqhs/sntrup761/kem/ntruprime/internal/Decode.go [new file with mode: 0644]
pqhs/sntrup761/kem/ntruprime/internal/Divmod.go [new file with mode: 0644]
pqhs/sntrup761/kem/ntruprime/internal/Encode.go [new file with mode: 0644]
pqhs/sntrup761/kem/ntruprime/sntrup761/ntruprime.go [new file with mode: 0644]
pqhs/sntrup761/pke/ntruprime/kem/kem.go [new file with mode: 0644]
pqhs/sntrup761/pke/ntruprime/kem/schemes/sntrup/schemes.go [new file with mode: 0644]
pqhs/sntrup761/pke/ntruprime/sntrup761/params.go [new file with mode: 0644]
pqhs/state.go [new file with mode: 0644]

index 44031a0a48b524712fba7c0716d637cdc5387b3210615347f153c18a859080b6..57b3a9c03643a5764a1180b8f6519ad6d9fdcc037314c4738fff119836902589 100644 (file)
@@ -19,7 +19,7 @@ import (
        "log"
 
        "go.stargrave.org/opus/v2"
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
 )
 
 func newOpusEnc() *opus.Encoder {
@@ -43,7 +43,7 @@ func newOpusEnc() *opus.Encoder {
 }
 
 func pcmConv(buf []byte, pcm []int16) {
-       for i := 0; i < len(pcm); i++ {
+       for i := range len(pcm) {
                buf[i*2+0] = byte((uint16(pcm[i]) & 0x00FF) >> 0)
                buf[i*2+1] = byte((uint16(pcm[i]) & 0xFF00) >> 8)
        }
index 6a6d8666823ac44ab66acd2706325c5f585819487b59e5f875cc7043abdb1a32..cc7a25330c46b3ea44e2be0f6fa6454d2f9cd3f0756ea60defccbaee6d89b608 100644 (file)
@@ -21,7 +21,7 @@ import (
        "sort"
 
        "github.com/jroimartin/gocui"
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
 )
 
 var (
index 134d84d2f32aff362f9442a7bad668b58a30b333229541a1cedb9b616e4aba7c..56ca2406f321393d99d04ae998b135bf21ab0f067ac2d659febdffd5acbe05b1 100644 (file)
@@ -17,8 +17,9 @@ package main
 
 import (
        "bytes"
+       "crypto/cipher"
+       "crypto/sha3"
        "crypto/subtle"
-       "encoding/base64"
        "encoding/binary"
        "flag"
        "fmt"
@@ -35,11 +36,10 @@ import (
        "github.com/aead/chacha20"
        "github.com/dchest/siphash"
        "github.com/jroimartin/gocui"
-       "github.com/katzenpost/noise"
-       "go.cypherpunks.su/netstring/v3"
        "go.stargrave.org/opus/v2"
-       vors "go.stargrave.org/vors/v4/internal"
-       "golang.org/x/crypto/blake2b"
+       vors "go.stargrave.org/vors/v5/internal"
+       "go.stargrave.org/vors/v5/pqhs"
+       "golang.org/x/crypto/chacha20poly1305"
 )
 
 type Stream struct {
@@ -63,16 +63,6 @@ var (
        Ctrl     = make(chan []byte)
 )
 
-func incr(data []byte) {
-       for i := len(data) - 1; i >= 0; i-- {
-               data[i]++
-               if data[i] != 0 {
-                       return
-               }
-       }
-       panic("overflow")
-}
-
 func muteToggle() (muted bool) {
        Muted = !Muted
        if Ctrl != nil {
@@ -90,7 +80,7 @@ func muteToggle() (muted bool) {
 func main() {
        srvAddr := flag.String("srv", "vors.home.arpa:"+strconv.Itoa(vors.DefaultPort),
                "host:TCP/UDP port to connect to")
-       srvPubB64 := flag.String("pub", "", "server's public key, Base64")
+       srvPubPth := flag.String("pub", "", "Path to server's public key")
        recCmd := flag.String("rec", "rec "+vors.SoxParams, "rec command")
        playCmd := flag.String("play", "play "+vors.SoxParams, "play command")
        vadRaw := flag.Uint("vad", 0, "VAD threshold")
@@ -135,11 +125,11 @@ Magenta "S" means that peer is locally muted.`)
 
        var passwdHsh []byte
        if *passwd != "" {
-               hsh := blake2b.Sum256([]byte(*passwd))
+               hsh := sha3.SumSHAKE128([]byte(*passwd), 32)
                passwdHsh = hsh[:]
        }
 
-       srvPub, err := base64.RawURLEncoding.DecodeString(*srvPubB64)
+       srvPub, err := os.ReadFile(*srvPubPth)
        if err != nil {
                log.Fatal(err)
        }
@@ -182,6 +172,11 @@ Magenta "S" means that peer is locally muted.`)
        }
 
        vors.PreferIPv4 = *prefer4
+       hs, buf, err := pqhs.NewClient(pqhs.KeyDecombine(srvPub))
+       if err != nil {
+               log.Fatalln("pqhs.NewClient:", err)
+       }
+
        ctrlConn, err := net.DialTCP("tcp", nil, vors.MustResolveTCP(*srvAddr))
        if err != nil {
                log.Fatalln("dial server:", err)
@@ -190,40 +185,50 @@ Magenta "S" means that peer is locally muted.`)
        if err = ctrlConn.SetNoDelay(true); err != nil {
                log.Fatalln("nodelay:", err)
        }
-       ctrl := vors.NewNSConn(ctrlConn)
-
-       hs, err := noise.NewHandshakeState(noise.Config{
-               CipherSuite: vors.NoiseCipherSuite,
-               Pattern:     noise.HandshakeNK,
-               Initiator:   true,
-               PeerStatic:  srvPub,
-               Prologue:    []byte(vors.NoisePrologue),
-       })
-       if err != nil {
-               log.Fatalln("noise.NewHandshakeState:", err)
+
+       ctrl := vors.NewNSConn(ctrlConn, 1<<16)
+       if err = ctrl.Tx([]byte(vors.Magic)); err != nil {
+               log.Fatalln("write handshake magic:", err)
        }
-       buf, _, _, err := hs.WriteMessage(nil, vors.ArgsEncode(
+       if err = ctrl.Tx(buf); err != nil {
+               log.Fatalln("write handshake hello:", err)
+       }
+       buf = <-ctrl.Rx
+       if buf == nil {
+               log.Fatalln("read handshake hello:", ctrl.Err)
+       }
+       buf, err = hs.Read(buf, vors.ArgsEncode(
                []byte(*Name), []byte(*Room), passwdHsh,
        ))
        if err != nil {
-               log.Fatalln("handshake encrypt:", err)
+               log.Fatalln("process handshake:", err)
        }
-       {
-               var w bytes.Buffer
-               w.WriteString(vors.NoisePrologue)
-               netstring.NewWriter(&w).WriteChunk(buf)
-               buf = w.Bytes()
+       if err = ctrl.Tx(buf); err != nil {
+               log.Fatalln("write handshake finish:", err)
        }
-       _, err = io.Copy(ctrlConn, bytes.NewReader(buf))
+
+       var txKey, rxKey, keyCiphOur, keyMACOur []byte
+       var txAEAD, rxAEAD cipher.AEAD
+       keys := hs.Binding(3*chacha20poly1305.KeySize + vors.SipHash24KeySize)
+       txKey, keys = keys[:chacha20poly1305.KeySize], keys[chacha20poly1305.KeySize:]
+       rxKey, keys = keys[:chacha20poly1305.KeySize], keys[chacha20poly1305.KeySize:]
+       keyCiphOur, keyMACOur = keys[:vors.ChaCha20KeySize], keys[vors.ChaCha20KeySize:]
+       txAEAD, err = chacha20poly1305.New(txKey)
        if err != nil {
-               log.Fatalln("write handshake:", err)
-               return
+               log.Fatal(err)
+       }
+       rxAEAD, err = chacha20poly1305.New(rxKey)
+       if err != nil {
+               log.Fatal(err)
        }
+       txNonce := make([]byte, chacha20poly1305.NonceSize)
+       rxNonce := make([]byte, chacha20poly1305.NonceSize)
+
        buf = <-ctrl.Rx
        if buf == nil {
-               log.Fatalln("read handshake:", ctrl.Err)
+               log.Fatalln("read handshake finish:", ctrl.Err)
        }
-       buf, txCS, rxCS, err := hs.ReadMessage(nil, buf)
+       buf, err = rxAEAD.Open(buf[:0], rxNonce, buf, nil)
        if err != nil {
                log.Fatalln("handshake decrypt:", err)
        }
@@ -231,12 +236,13 @@ Magenta "S" means that peer is locally muted.`)
        rx := make(chan []byte)
        go func() {
                for buf := range ctrl.Rx {
-                       buf, err = rxCS.Decrypt(buf[:0], nil, buf)
+                       buf, err = rxAEAD.Open(buf[:0], rxNonce, buf, nil)
                        if err != nil {
                                log.Println("rx decrypt", err)
                                break
                        }
                        rx <- buf
+                       vors.Incr(rxNonce)
                }
                Finish <- struct{}{}
        }()
@@ -312,23 +318,6 @@ Magenta "S" means that peer is locally muted.`)
                }
        }
 
-       var keyCiphOur []byte
-       var keyMACOur []byte
-       {
-               var xof blake2b.XOF
-               xof, err = blake2b.NewXOF(vors.ChaCha20KeySize+vors.SipHash24KeySize, nil)
-               if err != nil {
-                       log.Fatalln(err)
-               }
-               xof.Write([]byte(vors.NoisePrologue))
-               xof.Write(hs.ChannelBinding())
-               buf := make([]byte, vors.ChaCha20KeySize+vors.SipHash24KeySize)
-               if _, err = io.ReadFull(xof, buf); err != nil {
-                       log.Fatalln(err)
-               }
-               keyCiphOur, keyMACOur = buf[:vors.ChaCha20KeySize], buf[vors.ChaCha20KeySize:]
-       }
-
        seen := time.Now()
 
        LoggerReady := make(chan struct{})
@@ -387,13 +376,11 @@ Magenta "S" means that peer is locally muted.`)
 
        go func() {
                for buf := range Ctrl {
-                       buf, err = txCS.Encrypt(nil, nil, buf)
-                       if err != nil {
-                               log.Fatalln("tx encrypt:", err)
-                       }
+                       buf = txAEAD.Seal(nil, txNonce, buf, nil)
                        if err = ctrl.Tx(buf); err != nil {
                                log.Fatalln("tx:", err)
                        }
+                       vors.Incr(txNonce)
                }
        }()
 
@@ -686,11 +673,11 @@ Magenta "S" means that peer is locally muted.`)
                                log.Println("mic:", err)
                                break
                        }
-                       incr(actr[:])
+                       vors.Incr(actr[:])
                        if Muted {
                                continue
                        }
-                       for i = 0; i < vors.FrameLen; i++ {
+                       for i = range vors.FrameLen {
                                pcm[i] = int16(uint16(buf[i*2+0]) | (uint16(buf[i*2+1]) << 8))
                        }
                        if vad != 0 && vors.RMS(pcm) < vad {
@@ -705,7 +692,7 @@ Magenta "S" means that peer is locally muted.`)
                                continue
                        }
 
-                       incr(nonce[len(nonce)-3:])
+                       vors.Incr(nonce[len(nonce)-3:])
                        copy(buf, nonce[len(nonce)-4:])
                        copy(buf[4:], actr)
                        chacha20.XORKeyStream(
index a7b03bed4e16e35e72f4986e0a944db38c1da73f3e10e139e6b485ed1c8e2f29..cba958a6889447f4827fed3f539b1bc1b4019e589bc112d0bdcd66393bcf474b 100644 (file)
@@ -24,7 +24,7 @@ import (
 
        "github.com/dustin/go-humanize"
        "github.com/jroimartin/gocui"
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
 )
 
 type Stats struct {
index 31c06b3044050c6e60ee2c05746bd600394cefe7d416907c51f66c2777e139fd..ea611f01a977c9dd5c8d5c6a89491836ca6d9dd11944b14100ed5525ab4c579c 100644 (file)
@@ -1,22 +1,26 @@
 package main
 
 import (
-       "crypto/rand"
-       "encoding/base64"
+       "bytes"
        "flag"
        "fmt"
        "io"
        "log"
        "os"
 
-       "github.com/katzenpost/noise"
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
+       "go.stargrave.org/vors/v5/pqhs"
 )
 
+func usage() {
+       fmt.Fprintf(os.Stderr, "Usage: vors-keygen 5>pub 9>prv\n")
+       flag.PrintDefaults()
+}
+
 func main() {
-       pub := flag.Bool("pub", false, "print Base64 public key")
        version := flag.Bool("version", false, "print version")
        warranty := flag.Bool("warranty", false, "print warranty information")
+       flag.Usage = usage
        flag.Parse()
        if *warranty {
                fmt.Println(vors.Warranty)
@@ -26,21 +30,16 @@ func main() {
                fmt.Println(vors.GetVersion())
                return
        }
-       if *pub {
-               data, err := io.ReadAll(os.Stdin)
-               if err != nil {
-                       log.Fatal(err)
-               }
-               if len(data) != 2*32 {
-                       log.Fatal("wrong length")
-               }
-               fmt.Printf("%s\n", base64.RawURLEncoding.EncodeToString(data[32:]))
-               return
-       }
-       kp, err := noise.DH25519.GenerateKeypair(rand.Reader)
+       prvMcEliece, pubMcEliece, prvX25519, pubX25519, err := pqhs.KeyGen()
        if err != nil {
                log.Fatal(err)
        }
-       os.Stdout.Write(kp.Private[:])
-       os.Stdout.Write(kp.Public[:])
+       fdPubW := os.NewFile(5, "pub-out")
+       if _, err = io.Copy(fdPubW, bytes.NewReader(pqhs.KeyCombine(pubMcEliece, pubX25519))); err != nil {
+               log.Fatal(err)
+       }
+       fdPrvW := os.NewFile(9, "prv-out")
+       if _, err = io.Copy(fdPrvW, bytes.NewReader(pqhs.KeyCombine(prvMcEliece, prvX25519))); err != nil {
+               log.Fatal(err)
+       }
 }
index 6c62117936c5edecbeb3a95425f3776217b6e2b58a14b890b08d9df461781a56..2087dd5a397d2ddaac01220fd14835837ca6615927beb011d1e434c8f0b97571 100644 (file)
@@ -17,8 +17,8 @@ package main
 
 import (
        "crypto/rand"
+       "crypto/sha3"
        "crypto/subtle"
-       "encoding/base64"
        "flag"
        "fmt"
        "io"
@@ -33,14 +33,16 @@ import (
 
        "github.com/dchest/siphash"
        "github.com/jroimartin/gocui"
-       "github.com/katzenpost/noise"
-       vors "go.stargrave.org/vors/v4/internal"
-       "golang.org/x/crypto/blake2b"
+       vors "go.stargrave.org/vors/v5/internal"
+       "go.stargrave.org/vors/v5/pqhs"
+       "golang.org/x/crypto/chacha20poly1305"
 )
 
 var (
-       Prv, Pub []byte
-       Cookies  = map[vors.Cookie]chan *net.UDPAddr{}
+       PrvMcEliece []byte
+       PrvX25519   []byte
+       PubHash     []byte
+       Cookies     = map[vors.Cookie]chan *net.UDPAddr{}
 )
 
 func newPeer(conn *net.TCPConn) {
@@ -51,31 +53,35 @@ func newPeer(conn *net.TCPConn) {
        if err != nil {
                log.Fatalln("nodelay:", err)
        }
-       buf := make([]byte, len(vors.NoisePrologue))
-
-       if _, err = io.ReadFull(conn, buf); err != nil {
-               logger.Error("handshake: read prologue", "err", err)
+       nsConn := vors.NewNSConn(conn, 1<<16)
+       buf := <-nsConn.Rx
+       if buf == nil {
+               logger.Error("read magic", "err", nsConn.Err)
                return
        }
-       if string(buf) != vors.NoisePrologue {
-               logger.Error("handshake: wrong prologue", "err", err)
+       if string(buf) != vors.Magic {
+               logger.Error("handshake: wrong magic")
                return
        }
-
-       hs, err := noise.NewHandshakeState(noise.Config{
-               CipherSuite:   vors.NoiseCipherSuite,
-               Pattern:       noise.HandshakeNK,
-               Initiator:     false,
-               StaticKeypair: noise.DHKey{Private: Prv, Public: Pub},
-               Prologue:      []byte(vors.NoisePrologue),
-       })
+       buf = <-nsConn.Rx
+       if buf == nil {
+               logger.Error("handshake: read hello", "err", nsConn.Err)
+               return
+       }
+       hs, buf, err := pqhs.NewServer(PrvMcEliece, PrvX25519, PubHash, buf)
        if err != nil {
-               log.Fatalln("noise.NewHandshakeState:", err)
+               logger.Error("handshake: process hello", "err", err)
+               return
        }
-       nsConn := vors.NewNSConn(conn)
+       nsConn.Tx(buf)
        buf = <-nsConn.Rx
        if buf == nil {
-               logger.Error("read handshake", "err", nsConn.Err)
+               logger.Error("handshake: read finish", "err", nsConn.Err)
+               return
+       }
+       buf, err = hs.Read(buf)
+       if err != nil {
+               logger.Error("handshake: process finish", "err", err)
                return
        }
        peer := &Peer{
@@ -86,16 +92,27 @@ func newPeer(conn *net.TCPConn) {
                tx:     make(chan []byte, 10),
                alive:  make(chan struct{}),
        }
-       var room *Room
        {
-               var argsRaw []byte
-               argsRaw, _, _, err = hs.ReadMessage(nil, buf)
+               var rxKey, txKey []byte
+               keys := hs.Binding(3*chacha20poly1305.KeySize + vors.SipHash24KeySize)
+               rxKey, keys = keys[:chacha20poly1305.KeySize], keys[chacha20poly1305.KeySize:]
+               txKey, peer.key = keys[:chacha20poly1305.KeySize], keys[chacha20poly1305.KeySize:]
+               peer.mac = siphash.New(peer.key[vors.ChaCha20KeySize:])
+               peer.rxAEAD, err = chacha20poly1305.New(rxKey)
                if err != nil {
-                       logger.Error("handshake: decrypt", "err", err)
-                       return
+                       log.Fatal(err)
+               }
+               peer.txAEAD, err = chacha20poly1305.New(txKey)
+               if err != nil {
+                       log.Fatal(err)
                }
+       }
+       peer.rxNonce = make([]byte, chacha20poly1305.NonceSize)
+       peer.txNonce = make([]byte, chacha20poly1305.NonceSize)
+       var room *Room
+       {
                var args [][]byte
-               args, err = vors.ArgsDecode(argsRaw)
+               args, err = vors.ArgsDecode(buf)
                if err != nil {
                        logger.Error("handshake: decode args", "err", err)
                        return
@@ -141,13 +158,9 @@ func newPeer(conn *net.TCPConn) {
                }
                if room.key != key {
                        logger.Error("wrong password")
-                       buf, _, _, err = hs.WriteMessage(nil, vors.ArgsEncode(
+                       nsConn.Tx(peer.txAEAD.Seal(nil, peer.txNonce, vors.ArgsEncode(
                                []byte(vors.CmdErr), []byte("wrong password"),
-                       ))
-                       if err != nil {
-                               log.Fatal(err)
-                       }
-                       nsConn.Tx(buf)
+                       ), nil))
                        return
                }
        }
@@ -159,14 +172,10 @@ func newPeer(conn *net.TCPConn) {
                        continue
                }
                logger.Error("name already taken")
-               buf, _, _, err = hs.WriteMessage(nil, vors.ArgsEncode(
+               nsConn.Tx(peer.txAEAD.Seal(nil, peer.txNonce, vors.ArgsEncode(
                        []byte(vors.CmdErr), []byte("name already taken"),
-               ))
-               if err != nil {
-                       log.Fatal(err)
-               }
+               ), nil))
                room.peersM.RUnlock()
-               nsConn.Tx(buf)
                return
        }
        room.peersM.RUnlock()
@@ -189,13 +198,9 @@ func newPeer(conn *net.TCPConn) {
                }
                PeersM.Unlock()
                if !found {
-                       buf, _, _, err = hs.WriteMessage(nil, vors.ArgsEncode(
+                       nsConn.Tx(peer.txAEAD.Seal(nil, peer.txNonce, vors.ArgsEncode(
                                []byte(vors.CmdErr), []byte("too many users"),
-                       ))
-                       if err != nil {
-                               log.Fatal(err)
-                       }
-                       nsConn.Tx(buf)
+                       ), nil))
                        return
                }
        }
@@ -229,18 +234,14 @@ func newPeer(conn *net.TCPConn) {
                gotCookie := make(chan *net.UDPAddr)
                Cookies[cookie] = gotCookie
 
-               var txCS, rxCS *noise.CipherState
-               buf, txCS, rxCS, err := hs.WriteMessage(nil,
-                       vors.ArgsEncode([]byte(vors.CmdCookie), cookie[:]))
+               err = nsConn.Tx(peer.txAEAD.Seal(nil, peer.txNonce, vors.ArgsEncode(
+                       []byte(vors.CmdCookie), cookie[:],
+               ), nil))
                if err != nil {
-                       log.Fatalln("hs.WriteMessage:", err)
-               }
-               if err = nsConn.Tx(buf); err != nil {
                        logger.Error("handshake write", "err", err)
                        delete(Cookies, cookie)
                        return
                }
-               peer.rxCS, peer.txCS = txCS, rxCS
 
                timeout := time.NewTimer(vors.PingTime)
                select {
@@ -268,20 +269,6 @@ func newPeer(conn *net.TCPConn) {
        }
        room.peersM.RUnlock()
 
-       {
-               xof, err := blake2b.NewXOF(vors.ChaCha20KeySize+vors.SipHash24KeySize, nil)
-               if err != nil {
-                       log.Fatalln(err)
-               }
-               xof.Write([]byte(vors.NoisePrologue))
-               xof.Write(hs.ChannelBinding())
-               peer.key = make([]byte, vors.ChaCha20KeySize+vors.SipHash24KeySize)
-               if _, err = io.ReadFull(xof, peer.key); err != nil {
-                       log.Fatalln(err)
-               }
-               peer.mac = siphash.New(peer.key[vors.ChaCha20KeySize:])
-       }
-
        {
                s := vors.ArgsEncode(
                        []byte(vors.CmdAdd), []byte{peer.sid}, []byte(peer.name), peer.key)
@@ -368,13 +355,14 @@ func newPeer(conn *net.TCPConn) {
 func main() {
        bind := flag.String("bind", "[::1]:"+strconv.Itoa(vors.DefaultPort),
                "host:TCP/UDP port to listen on")
-       kpFile := flag.String("key", "key", "path to keypair file")
+       pubFile := flag.String("pub", "pub", "path to file with public key")
+       prvFile := flag.String("prv", "prv", "path to file with private key")
        prefer4 := flag.Bool("4", false,
                "Prefer obsolete legacy IPv4 address during name resolution")
        version := flag.Bool("version", false, "print version")
        warranty := flag.Bool("warranty", false, "print warranty information")
        flag.Usage = func() {
-               fmt.Fprintln(os.Stderr, "Usage: vors-server [opts] -bind HOST:PORT -key PATH -srv HOST:PORT")
+               fmt.Fprintln(os.Stderr, "Usage: vors-server [opts] -bind HOST:PORT -prv PRV -pub PUB -srv HOST:PORT")
                flag.PrintDefaults()
                fmt.Fprintln(os.Stderr, `
 List of known rooms is shown by default. If room requires password
@@ -399,11 +387,16 @@ Press F10 to quit.`)
        }
 
        {
-               data, err := os.ReadFile(*kpFile)
+               prv, err := os.ReadFile(*prvFile)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               PrvMcEliece, PrvX25519 = pqhs.KeyDecombine(prv)
+               pub, err := os.ReadFile(*pubFile)
                if err != nil {
                        log.Fatal(err)
                }
-               Prv, Pub = data[:len(data)/2], data[len(data)/2:]
+               PubHash = sha3.SumSHAKE256(pub, 64)
        }
 
        vors.PreferIPv4 = *prefer4
@@ -542,9 +535,7 @@ Press F10 to quit.`)
 
        go func() {
                <-LoggerReady
-               slog.Info("listening",
-                       "bind", *bind,
-                       "pub", base64.RawURLEncoding.EncodeToString(Pub))
+               slog.Info("listening", "bind", *bind)
                for {
                        conn, errConn := lnTCP.AcceptTCP()
                        if err != nil {
index 288b4d6659a9a21b90ebddb3ccbc2e5c5dc6bda3f81a8fa3468f5efbec211208..dbb554231cde2fb0bbf4e87b8dfbf721170680d0971329aeef29fcead51b2778 100644 (file)
@@ -1,14 +1,14 @@
 package main
 
 import (
+       "crypto/cipher"
        "hash"
        "log/slog"
        "net"
        "sync"
        "time"
 
-       "github.com/katzenpost/noise"
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
 )
 
 var (
@@ -35,12 +35,15 @@ type Peer struct {
        muted bool
        sid   byte
 
-       logger     *slog.Logger
-       conn       *vors.NSConn
-       rxCS, txCS *noise.CipherState
-       rx, tx     chan []byte
-       alive      chan struct{}
-       aliveOnce  sync.Once
+       logger    *slog.Logger
+       conn      *vors.NSConn
+       rxAEAD    cipher.AEAD
+       txAEAD    cipher.AEAD
+       rxNonce   []byte
+       txNonce   []byte
+       rx, tx    chan []byte
+       alive     chan struct{}
+       aliveOnce sync.Once
 }
 
 func (peer *Peer) Close() {
@@ -55,12 +58,13 @@ func (peer *Peer) Close() {
 func (peer *Peer) Rx() {
        var err error
        for buf := range peer.conn.Rx {
-               buf, err = peer.rxCS.Decrypt(buf[:0], nil, buf)
+               buf, err = peer.rxAEAD.Open(buf[:0], peer.rxNonce, buf, nil)
                if err != nil {
                        peer.logger.Error("rx decrypt", "err", err)
                        break
                }
                peer.rx <- buf
+               vors.Incr(peer.rxNonce)
        }
        peer.Close()
 }
@@ -68,18 +72,12 @@ func (peer *Peer) Rx() {
 func (peer *Peer) Tx() {
        var err error
        for buf := range peer.tx {
-               if peer.txCS == nil {
-                       continue
-               }
-               buf, err = peer.txCS.Encrypt(buf[:0], nil, buf)
-               if err != nil {
-                       peer.logger.Error("tx encrypt", "err", err)
-                       break
-               }
+               buf = peer.txAEAD.Seal(buf[:0], peer.txNonce, buf, nil)
                if err = peer.conn.Tx(buf); err != nil {
                        peer.logger.Error("tx write", "err", err)
                        break
                }
+               vors.Incr(peer.txNonce)
        }
        peer.Close()
 }
index 5e40cacc3e6ab4e6ed3e8a85c1d86d9089ae8813011dac7b45c8cf17691468bd..f55e596a1181fd9e476d1feb710cfb3597c44b2d545fba95d99b4618c241f8ce 100644 (file)
@@ -8,7 +8,7 @@ import (
        "time"
 
        "github.com/dustin/go-humanize"
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
 )
 
 var (
index dc44b399ec5305c8ff4c51dd234f44bcc4b376cdedec11898e385429ac0a7eac..b1ae1461e5e766c916b9a407d145325a48e38e35f154ecd67657fa33379c1a47 100644 (file)
@@ -23,7 +23,7 @@ import (
        "os"
        "strconv"
 
-       vors "go.stargrave.org/vors/v4/internal"
+       vors "go.stargrave.org/vors/v5/internal"
 )
 
 func usage() {
@@ -62,7 +62,7 @@ func main() {
                if err != nil {
                        log.Fatal(err)
                }
-               for i = 0; i < vors.FrameLen; i++ {
+               for i = range vors.FrameLen {
                        pcm[i] = int16(uint16(buf[i*2+0]) | (uint16(buf[i*2+1]) << 8))
                }
                rms = vors.RMS(pcm)
index fe75832d4385591cb1a816d20e1c33beefd5209ece27a053a4b4b68493fd12c7..5d596385153dcdafa383c9da929acf80429e444cf0486256e43bb164fa2fc2b2 100644 (file)
@@ -5,11 +5,11 @@
   and DTX (discontinuous transmission) features enabled. Optional [VAD]
   (voice activity detection).
   => https://opus-codec.org/ Opus codec\r
-* Noise-NKhfs protocol-based 0-RTT single round-trip handshake over TCP
-  between client and server for creating authenticated encrypted channel
-  and authentication based on server's public key knowledge.
+* PQConnect and Noise inspired post-quantum secure handshake protocol
+  over TCP between client and server. Authentication is based on
+  server's public key knowledge.
+  => https://www.pqconnect.net/ PQConnect\r
   => http://noiseprotocol.org/ Noise protocol framework\r
-  => https://github.com/noiseprotocol/noise_hfs_spec KEM-based hybrid forward secrecy\r
 * Fast ChaCha20 encryption with SipHash24 message authentication.
 * Rooms, optionally password protected. Peers are able to broadcast
   text message to everyone in the room.
index 7f3a47ab10ac8272ec80a6173abe7a01661b734dc7ec05214c141451b557c034..ea7ac86a5409bbefb3079e5061c362586cd4661445449541d97c0aac27b8c8e3 100644 (file)
@@ -1,4 +1,4 @@
-VoRS is written on Go (at least 1.21 version is required), but also uses
+VoRS is written on Go (at least 1.24 version is required), but also uses
 wrapper on libopus library. Provided tarballs include its source code
 and a fork of the gopkg.in/hraban/opus.v2 with the added ability to use
 Decoder.SetComplexity call, that is required for ML-related optimisations.
@@ -16,7 +16,7 @@ them with -rec and -play options to vors-client.
 
 => https://sourceforge.net/projects/sox/ SoX\r
 
-    $ version=4.0.0
+    $ version=5.0.0
     $ [fetch|wget] http://www.vors.stargrave.org/download/vors-$version.tar.zst
     $ [fetch|wget] http://www.vors.stargrave.org/download/vors-$version.tar.zst.sig
     [verify signature]
diff --git a/doc/PQHS b/doc/PQHS
new file mode 100644 (file)
index 0000000..128147c
--- /dev/null
+++ b/doc/PQHS
@@ -0,0 +1,51 @@
+Server has a long-term static Classic McEliece 6960-119 and X25519
+keypairs. They are transferred to client outside the connection.
+
+Client:
+    * has: serverStaticPubMcEliece, serverStaticPubX25519
+    * clientEphPrvX25519, clientEphPubX25519 = Generate()
+    * ctMcElice, ssMcEliece = Encapsulate(serverStaticPubMcEliece)
+    * H = SHAKE256("VoRS v5")
+    * H = SHAKE256(H || serverStaticPubMcEliece || serverStaticPubX25519)
+    * H = SHAKE256(H || ctMcElice)
+    * CK = HKDF-Extract(SHAKE256, ikm=ssMcEliece, salt="")
+    * k = HKDF-Expand(SHAKE256, prk=CK, info="VoRS v5 client x25519")
+    * ctX25519 = ChaCha20-Poly1305(k, nonce=0, ad=H, pt=clientEphPubX25519)
+    * H = SHAKE256(H || ctX25519)
+    * ssX25519 = X25519(clientEphPrvX25519, serverStaticPubX25519)
+    * CK = HKDF-Extract(SHAKE256, ikm=ssX25519, salt=CK)
+    * sends: ctMcElice || ctX25519
+
+Server:
+    * ...
+    * serverEphPrvX25519, serverEphPubX25519 = Generate()
+    * k = HKDF-Expand(SHAKE256, prk=CK, info="VoRS v5 server x25519")
+    * ctX25519 = ChaCha20-Poly1305(k, nonce=0, ad=H, pt=serverEphPubX25519)
+    * H = SHAKE256(H || ctX25519)
+    * ssX25519 = X25519(serverEphPrvX25519, clientEphPubX25519)
+    * CK = HKDF-Extract(SHAKE256, ikm=ssX25519, salt=CK)
+    * serverEphPrvSNTRUP761, serverEphPubSNTRUP761 = Generate()
+    * k = HKDF-Expand(SHAKE256, prk=CK, info="VoRS v5 server sntrup761")
+    * ctSNTRUP = ChaCha20-Poly1305(k, nonce=0, ad=H, pt=serverEphPubSNTRUP761)
+    * H = SHAKE256(H || ctSNTRUP)
+    * sends: ctX25519 || ctSNTRUP
+
+Client:
+    * has: prefinish message payload
+    * ...
+    * ctSNTRUP, ssSNTRUP = Encapsulate(serverEphPubSNTRUP761)
+    * k = HKDF-Expand(SHAKE256, prk=CK, info="VoRS v5 client sntrup761")
+    * ctSNTRUP = ChaCha20-Poly1305(k, nonce=0, ad=H, pt=ctSNTRUP)
+    * H = SHAKE256(H || ctSNTRUP)
+    * CK = HKDF-Extract(SHAKE256, ikm=ssSNTRUP, salt=CK)
+    * k = HKDF-Expand(SHAKE256, prk=CK, info="VoRS v5 client prefinish")
+    * ctPrefinish = ChaCha20-Poly1305(k, nonce=0, ad=H, pt=prefinish)
+    * H = SHAKE256(H || ctPrefinish)
+    * sends: ctPrefinish
+
+Server:
+    * ...
+
+Both:
+    clientChaPolyKey, serverChaPolyKey, VoIPKey =
+        HKDF-Expand(SHAKE256, ikm=CK, salt=H)
index 09d8030e144df630b85f7063435836a1a0c9063e41b97aac430e394f6fcb5c54..25374872391ed5ef558ec313e6b0845c0c2254ef443384f023a201abab7bd080 100644 (file)
@@ -13,30 +13,41 @@ ability to distinguish jitters and delays from lack of audio
 transmission.
 
 Each packet is encrypted with ChaCha20 and authenticated with SipHash24.
-Their keys are generated from BLAKE2b-XOF, which is fed with completed
-handshake's binding value. Then they are shared among the other
-participants. The stream identifier together with the packet counter is
-used as a nonce.
+Their keys are generated with HKDF taken on handshake's state. Then they
+are shared among the other participants. The stream identifier together
+with the packet counter is used as a nonce.
 
 It is tuned for 24Kbps bandwidth. But remember that it has additional 8B
 of MAC tag, 7B VoRS, 8B UDP and 40B IPv6 headers.
 
 Each client handshakes with the server over TCP connection using the
-Noise-NKhfs protocol pattern with curve25519, Kyber-1024, ChaCha20-Poly1305
-and BLAKE2b algorithms.
-=> http://noiseprotocol.org/ Noise protocol framework\r
-=> https://github.com/noiseprotocol/noise_hfs_spec KEM-based hybrid forward secrecy\r
-
-* Client sends "VoRS v4" to the socket. Just a magic number.
+PQConnect, Noise, Chempat inspired protocol. It consists of hybrid key
+exchange, using static Classic McEliece 6960-119 server's public key,
+static X25519, ephemeral X25519 and ephemeral Streamlined NTRU Prime 761
+ones. With HKDF as a KDF and SHAKE as a hash function.
 
-* All next messages are Netstring encoded strings. Most of them contain
+=> https://www.pqconnect.net/ PQConnect\r
+=> http://noiseprotocol.org/ Noise protocol framework\r
+=> https://datatracker.ietf.org/doc/draft-josefsson-chempat/ Chempat\r
+=> https://classic.mceliece.org/ Classic McEliece\r
+=> https://ntruprime.cr.yp.to/ Streamlined NTRU Prime\r
+=> https://datatracker.ietf.org/doc/html/rfc7748 X25519\r
+=> https://datatracker.ietf.org/doc/html/rfc5869.html HKDF\r
+=> https://keccak.team/ SHAKE\r
+
+* All messages are Netstring encoded strings. Most of them contain
   netstring encoded sequence of netstrings if multiple values are expected:
     NS(NS(arg0) || NS(arg1) || ...)
   => http://cr.yp.to/proto/netstrings.txt Netstring\r
 
-* Client sends initial Noise handshake message with his username, room
-  name and optional BLAKE2b-256 hash of the room's password (or an empty
-  string) as a payload: [USERNAME, ROOM, hash(PASSWD)].
+* Client sends NS("VoRS v5") to the socket. Just a magic number.
+
+* Then it performs [PQHS].
+
+* Client sends initial handshake message. Its prefinish payload message
+  contains his username, room name and optional SHAKE256 hash of the
+  room's password (or an empty string) as a payload:
+  [USERNAME, ROOM, hash(PASSWD)].
 
 * Server answers with final noise handshake message with the
   ["COOKIE", COOKIE], or ["ERR", MSG] failure message. It may reject a
@@ -56,10 +67,14 @@ and BLAKE2b algorithms.
 * Server replies with ["SID", SID], where SID is single byte stream
   number client must use.
 
+TODO
+
 * ["PING"] and ["PONG"] messages are then sent every ten seconds as a heartbeat.
 
-    S <- C : e, es, e1, NS(NS(USERNAME) || NS(ROOM) || NS(hash(PASSWD)))
-    S -> C : e, ee, ekem1, NS(NS("COOKIE") || NS(COOKIE))
+    S <- C : hello
+    S -> C : hello
+    S <- C : finish, NS(NS(USERNAME) || NS(ROOM) || NS(hash(PASSWD)))
+    S -> C : NS(NS("COOKIE") || NS(COOKIE))
     S <- C : UDP(COOKIE)
     S -> C : NS(NS("SID") || NS(SID))
 
index a3252a0da8d14866d5ad380194f951817105f9db080f69aef5032d80e40ee320..dabe006aa471a15cb268e5af5513c4a8c87351a09d1e8461c77ef97959952b19 100644 (file)
--- a/doc/Usage
+++ b/doc/Usage
@@ -1,8 +1,8 @@
 * Generate server's keypair. And share its public key among users.
   Fact of server's public key knowledge means ability to connect to it.
 
-    $ vors-keygen | tee key | vors-keygen -pub | read pub
-    $ vors-server -key key -bind [2001:db8::1]:12978
+    $ vors-keygen 5>pub 9>prv
+    $ vors-server -prv prv -pub pub -bind [2001:db8::1]:12978
 
 * Client uses external commands for reading from microphone and playing
   it back. By default it uses SoX'es "rec" and "play" commands.
@@ -16,7 +16,7 @@
 
 * Start the client, providing server's public key and our username:
 
-    $ vors-client -srv "[2001:db8::1]:12978" -pub $pub -name NAME
+    $ vors-client -srv "[2001:db8::1]:12978" -pub pub -name NAME
 
   Pressing F10 in server/client TUIs means quitting.
   Pressing F1 in client means "mute" toggling.
index 6438376a11d75e8bdb3537d720362ad2aabd3b02570cbf2f9e4fb7f16f4a8f5c..37c12eb684f16fa349dee8240795883c6ad65c034a06e41b8de0a3ccd7c590e6 100644 (file)
--- a/doc/index
+++ b/doc/index
@@ -27,7 +27,7 @@ the key to just immediately talk with someone.
   application? But a fancy real-time refreshing TUI would be desirable.
   Mumble tends to output no information, sometimes hiding the fact of a
   problem and that everything stopped working.
-* Mono-cypher, mono-codec protocol.
+* Mono-codec, mono-cypher, post-quantum ready protocol.
 * Maximal easiness of usage: here is your address, key, do me good.
 
 VoRS is copylefted free software licenced under GNU Affero GPLv3.
diff --git a/go.mod b/go.mod
index b2177e7fb0c5678f66d1c73a7f7b0ffe3d7c3735a5683f0f469ecaec893fbfdb..20341b5cb8d6b7e40baf374a31e36da01dd3c354d713ab9933ae5d29f3878437 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -1,22 +1,20 @@
-module go.stargrave.org/vors/v4
+module go.stargrave.org/vors/v5
 
-go 1.23.0
+go 1.24.0
 
-toolchain go1.24.3
+toolchain go1.24.5
 
 require (
        github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
        github.com/dchest/siphash v1.2.3
        github.com/dustin/go-humanize v1.0.1
        github.com/jroimartin/gocui v0.5.0
-       github.com/katzenpost/noise v0.0.3
        go.cypherpunks.su/netstring/v3 v3.0.0
        go.stargrave.org/opus/v2 v2.1.0
        golang.org/x/term v0.32.0
 )
 
 require (
-       github.com/cloudflare/circl v1.6.1 // indirect
        github.com/mattn/go-runewidth v0.0.9 // indirect
        github.com/nsf/termbox-go v1.1.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 1cbbddf0eb24c0eb9e5ab3f9fd9b21d5c03d896d4197ebee6a5e87f171177d96..34e5b3f0e5440f95ee658efb8f86a29c635074995d782ee78237ea53d79c9f17 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -1,22 +1,11 @@
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
-github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
-github.com/cloudflare/circl v1.0.1-0.20210824050549-9b4298fa53ce/go.mod h1:wqo+yhCGS0T5Ldpb0f4hdJqVGwsEBYDE3MrO6W/RACc=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
 github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
 github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/jroimartin/gocui v0.5.0 h1:DCZc97zY9dMnHXJSJLLmx9VqiEnAj0yh0eTNpuEtG/4=
 github.com/jroimartin/gocui v0.5.0/go.mod h1:l7Hz8DoYoL6NoYnlnaX6XCNR62G7J5FfSW5jEogzaxE=
-github.com/katzenpost/noise v0.0.3 h1:bpYnozkk8j0XE1FAX9iRYgKtfIywuAINF+vMdBOidrM=
-github.com/katzenpost/noise v0.0.3/go.mod h1:+3UhOI7g4gXPlAdRKdgMKmxZmK/PP1/3sCnX20SA/vQ=
-github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
@@ -25,21 +14,9 @@ go.cypherpunks.su/netstring/v3 v3.0.0 h1:wwFjxTb/LZM8cQN/UiOPMO5wcuq4xCQWdLAYz74
 go.cypherpunks.su/netstring/v3 v3.0.0/go.mod h1:S9pYNVqT6kL2uXbdHz+yxc+A4sAFxBkjSzu+g6KD0QE=
 go.stargrave.org/opus/v2 v2.1.0 h1:WwyMf76wcIWEPIQlU2UI5V9YkqXRHQhq6wfZGslcMFc=
 go.stargrave.org/opus/v2 v2.1.0/go.mod h1:Y57qgcaXH7jBvKW89fscWOT/Wd3MYfhXUbYUcOMV0A8=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
 golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
 golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
 golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/internal/incr.go b/internal/incr.go
new file mode 100644 (file)
index 0000000..5b501e7
--- /dev/null
@@ -0,0 +1,11 @@
+package internal
+
+func Incr(data []byte) {
+       for i := len(data) - 1; i >= 0; i-- {
+               data[i]++
+               if data[i] != 0 {
+                       return
+               }
+       }
+       panic("overflow")
+}
diff --git a/internal/noise.go b/internal/noise.go
deleted file mode 100644 (file)
index 36e7eb8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package internal
-
-import (
-       "github.com/katzenpost/noise"
-)
-
-const NoisePrologue = "VoRS v4"
-
-var NoiseCipherSuite = noise.NewCipherSuiteHFS(
-       noise.DH25519,
-       noise.CipherChaChaPoly,
-       noise.HashBLAKE2b,
-       noise.HFSKyber,
-)
index 4c271bf5a20a82a9cb9b502c18754a70141ee1b175c7183f23e05fa96bccd2e0..b23a1de2e4c558b2365d800ac9bd0c1b6ae23b126900b9a53b70238c3688cabb 100644 (file)
@@ -45,14 +45,15 @@ func ArgsDecode(buf []byte) (args [][]byte, err error) {
 }
 
 type NSConn struct {
-       Conn net.Conn
-       Rx   chan []byte
-       Err  error
+       Conn   net.Conn
+       Rx     chan []byte
+       Err    error
+       MaxLen uint64
        sync.Mutex
 }
 
-func NewNSConn(conn net.Conn) *NSConn {
-       c := NSConn{Conn: conn, Rx: make(chan []byte)}
+func NewNSConn(conn net.Conn, maxLen int) *NSConn {
+       c := NSConn{Conn: conn, Rx: make(chan []byte), MaxLen: uint64(maxLen)}
        go func() {
                r := netstring.NewReader(conn)
                var n uint64
@@ -61,6 +62,10 @@ func NewNSConn(conn net.Conn) *NSConn {
                        if c.Err != nil {
                                break
                        }
+                       if n >= c.MaxLen {
+                               c.Err = errors.New("exceeds MaxLen")
+                               break
+                       }
                        buf := make([]byte, int(n))
                        if _, c.Err = io.ReadFull(r, buf); c.Err != nil {
                                break
index 2cb501d58961996c23762668791718e823adec7c15f82a4fb5893e85497c4aae..cd354241d4abbd9dcc9c1cf36b278ceea40d030ff02178e5b09fe8fbb1627a31 100644 (file)
@@ -6,6 +6,7 @@ import (
 )
 
 const (
+       Magic      = "VoRS v5"
        CmdErr     = "ERR"
        CmdCookie  = "COOKIE"
        CmdSID     = "SID"
index e5a5dc31ce91d00ffd7c6600bcf04833f021fcb6f2467e6d74bd8f676659049c..61beb15d799bd76e454b257d7967abdf9c680dca0ddb30c3407a741d9bf2765d 100755 (executable)
--- a/makedist
+++ b/makedist
@@ -46,7 +46,6 @@ meta4ra-create -fn "$tarball" -mtime "$tarball" \
 size=$(( $(stat -f %z $tarball) / 1024 ))
 release_date=$(date "+%Y-%m-%d")
 
-release_underscored=`echo $release | tr . _`
 cat <<EOF
 An entry for documentation:
 $release | $release_date | $size KiB
diff --git a/pqhs/client.go b/pqhs/client.go
new file mode 100644 (file)
index 0000000..1c4dd16
--- /dev/null
@@ -0,0 +1,100 @@
+package pqhs
+
+import (
+       "crypto/ecdh"
+       "crypto/rand"
+       "crypto/sha3"
+
+       vors "go.stargrave.org/vors/v5/internal"
+       "go.stargrave.org/vors/v5/pqhs/mceliece6960119"
+       sntrup761kem "go.stargrave.org/vors/v5/pqhs/sntrup761/kem"
+       sntrup761 "go.stargrave.org/vors/v5/pqhs/sntrup761/kem/ntruprime/sntrup761"
+       "golang.org/x/crypto/chacha20poly1305"
+)
+
+type Client struct {
+       ephPrvX25519 *ecdh.PrivateKey
+       SymmetricState
+}
+
+func NewClient(
+       serverStaticPubMcElieceRaw, serverStaticPubX25519Raw []byte,
+) (c *Client, payload []byte, err error) {
+       c = &Client{}
+       var serverStaticPubMcEliece *mceliece6960119.PublicKey
+       serverStaticPubMcEliece, err = mceliece6960119.UnmarshalBinaryPublicKey(
+               serverStaticPubMcElieceRaw)
+       if err != nil {
+               return
+       }
+       var serverStaticPubX25519 *ecdh.PublicKey
+       {
+               x25519 := ecdh.X25519()
+               serverStaticPubX25519, err = x25519.NewPublicKey(serverStaticPubX25519Raw)
+               if err != nil {
+                       return
+               }
+               c.ephPrvX25519, err = x25519.GenerateKey(rand.Reader)
+               if err != nil {
+                       return
+               }
+       }
+       var ctMcEliece []byte
+       var k []byte
+       ctMcEliece, k, err = mceliece6960119.Encapsulate(serverStaticPubMcEliece)
+       if err != nil {
+               return
+       }
+       c.H([]byte(vors.Magic))
+       c.H(sha3.SumSHAKE256(
+               append(serverStaticPubMcElieceRaw, serverStaticPubX25519Raw...), 64))
+       c.H(ctMcEliece)
+       c.CK(k)
+       payload = append(ctMcEliece,
+               c.Seal(CtxClientX25519, c.ephPrvX25519.PublicKey().Bytes())...)
+       k, err = c.ephPrvX25519.ECDH(serverStaticPubX25519)
+       if err == nil {
+               c.CK(k)
+       }
+       return
+}
+
+func (c *Client) Read(reply, prefinish []byte) (payload []byte, err error) {
+       ctX25519 := reply[:32+chacha20poly1305.Overhead]
+       ctSNTRUP := reply[len(ctX25519):]
+       var k []byte
+       {
+               var serverEphPubX25519Raw []byte
+               serverEphPubX25519Raw, err = c.Open(CtxServerX25519, ctX25519)
+               if err != nil {
+                       return
+               }
+               _, k, err = DH(c.ephPrvX25519, serverEphPubX25519Raw)
+               if err != nil {
+                       return
+               }
+       }
+       c.CK(k)
+       {
+               var serverEphPubSNTRUPRaw []byte
+               serverEphPubSNTRUPRaw, err = c.Open(CtxServerSNTRUP761, ctSNTRUP)
+               if err != nil {
+                       return
+               }
+               sntrup761s := sntrup761.Scheme()
+               var serverEphPubSNTRUP sntrup761kem.PublicKey
+               serverEphPubSNTRUP, err = sntrup761s.UnmarshalBinaryPublicKey(
+                       serverEphPubSNTRUPRaw)
+               if err != nil {
+                       return
+               }
+               ctSNTRUP, k, err = sntrup761s.Encapsulate(serverEphPubSNTRUP)
+               if err != nil {
+                       return
+               }
+       }
+       ctSNTRUP = c.Seal(CtxClientSNTRUP761, ctSNTRUP)
+       c.CK(k)
+       payload = append(ctSNTRUP, c.Seal(CtxClientPrefinish, prefinish)...)
+       return
+}
diff --git a/pqhs/const.go b/pqhs/const.go
new file mode 100644 (file)
index 0000000..c5df1e2
--- /dev/null
@@ -0,0 +1,9 @@
+package pqhs
+
+const (
+       CtxClientX25519    = "VoRS v5 client x25519"
+       CtxServerX25519    = "VoRS v5 server x25519"
+       CtxServerSNTRUP761 = "VoRS v5 server sntrup761"
+       CtxClientSNTRUP761 = "VoRS v5 client sntrup761"
+       CtxClientPrefinish = "VoRS v5 client prefinish"
+)
diff --git a/pqhs/dh.go b/pqhs/dh.go
new file mode 100644 (file)
index 0000000..208e36d
--- /dev/null
@@ -0,0 +1,13 @@
+package pqhs
+
+import "crypto/ecdh"
+
+func DH(prv *ecdh.PrivateKey, pubRaw []byte) (pub *ecdh.PublicKey, k []byte, err error) {
+       x25519 := ecdh.X25519()
+       pub, err = x25519.NewPublicKey(pubRaw)
+       if err != nil {
+               return
+       }
+       k, err = prv.ECDH(pub)
+       return
+}
diff --git a/pqhs/hs_test.go b/pqhs/hs_test.go
new file mode 100644 (file)
index 0000000..c26e8de
--- /dev/null
@@ -0,0 +1,44 @@
+package pqhs
+
+import (
+       "bytes"
+       "crypto/sha3"
+       "testing"
+)
+
+func TestHandshake(t *testing.T) {
+       prvMcEliece, pubMcEliece, prvX25519, pubX25519, err := KeyGen()
+       if err != nil {
+               t.Fatal(err)
+       }
+       var c *Client
+       var payload []byte
+       c, payload, err = NewClient(KeyDecombine(KeyCombine(pubMcEliece, pubX25519)))
+       if err != nil {
+               t.Fatal(err)
+       }
+       var s *Server
+       prvMcEliece, prvX25519 = KeyDecombine(KeyCombine(prvMcEliece, prvX25519))
+       s, payload, err = NewServer(
+               prvMcEliece, prvX25519,
+               sha3.SumSHAKE256(append(pubMcEliece, pubX25519...), 64),
+               payload)
+       if err != nil {
+               t.Fatal(err)
+       }
+       payload, err = c.Read(payload, []byte("whatever"))
+       if err != nil {
+               t.Fatal(err)
+       }
+       var prefinish []byte
+       prefinish, err = s.Read(payload)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if string(prefinish) != "whatever" {
+               t.Fatal("prefinish differs")
+       }
+       if !bytes.Equal(c.Binding(1234), s.Binding(1234)) {
+               t.Fatal("bindings differs")
+       }
+}
diff --git a/pqhs/key.go b/pqhs/key.go
new file mode 100644 (file)
index 0000000..5a6003e
--- /dev/null
@@ -0,0 +1,53 @@
+package pqhs
+
+import (
+       "crypto/ecdh"
+       "crypto/rand"
+
+       "go.stargrave.org/vors/v5/pqhs/mceliece6960119"
+)
+
+func KeyGen() (
+       prvMcEliece, pubMcEliece, prvX25519, pubX25519 []byte, err error,
+) {
+       {
+               x25519 := ecdh.X25519()
+               var prv *ecdh.PrivateKey
+               prv, err = x25519.GenerateKey(rand.Reader)
+               if err != nil {
+                       return
+               }
+               prvX25519 = prv.Bytes()
+               pubX25519 = prv.PublicKey().Bytes()
+       }
+       {
+               var pub *mceliece6960119.PublicKey
+               var prv *mceliece6960119.PrivateKey
+               pub, prv, err = mceliece6960119.GenerateKeyPair()
+               if err != nil {
+                       return
+               }
+               prvMcEliece, err = prv.MarshalBinary()
+               if err != nil {
+                       return
+               }
+               pubMcEliece, err = pub.MarshalBinary()
+               if err != nil {
+                       return
+               }
+       }
+       return
+}
+
+func KeyCombine(mcEliece, x25519 []byte) []byte {
+       return append(mcEliece, x25519...)
+}
+
+func KeyDecombine(combined []byte) (mcEliece, x25519 []byte) {
+       if len(combined) <= 32 {
+               panic("too short combined key")
+       }
+       mcEliece = combined[:len(combined)-32]
+       x25519 = combined[len(combined)-32:]
+       return
+}
diff --git a/pqhs/mceliece6960119/README b/pqhs/mceliece6960119/README
new file mode 100644 (file)
index 0000000..e285c3b
--- /dev/null
@@ -0,0 +1,4 @@
+Go/Git is unable to fetch (https://github.com/cloudflare/circl)
+pull-request's commit (7dfc396c96830ed3601ace705e1612b9bcc447f9) to
+github.com/cloudflare/circl containing mceliece6960119 implementation
+(https://github.com/cloudflare/circl/pull/378). So copy it here.
diff --git a/pqhs/mceliece6960119/benes.go b/pqhs/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/pqhs/mceliece6960119/fft.go b/pqhs/mceliece6960119/fft.go
new file mode 100644 (file)
index 0000000..1d117de
--- /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.stargrave.org/vors/v5/pqhs/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/pqhs/mceliece6960119/internal/controlbits.go b/pqhs/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/pqhs/mceliece6960119/internal/djbsort.go b/pqhs/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/pqhs/mceliece6960119/internal/fft_const.go b/pqhs/mceliece6960119/internal/fft_const.go
new file mode 100644 (file)
index 0000000..476eb3f
--- /dev/null
@@ -0,0 +1,3096 @@
+package internal
+
+import (
+       "go.stargrave.org/vors/v5/pqhs/mceliece6960119/math/gf2e12"
+       "go.stargrave.org/vors/v5/pqhs/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/pqhs/mceliece6960119/internal/powers.go b/pqhs/mceliece6960119/internal/powers.go
new file mode 100644 (file)
index 0000000..2d4c391
--- /dev/null
@@ -0,0 +1,2828 @@
+package internal
+
+import (
+       "go.stargrave.org/vors/v5/pqhs/mceliece6960119/math/gf2e12"
+       "go.stargrave.org/vors/v5/pqhs/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/pqhs/mceliece6960119/math/gf2e12/gf4096.go b/pqhs/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/pqhs/mceliece6960119/math/gf2e13/gf8192.go b/pqhs/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/pqhs/mceliece6960119/mceliece.go b/pqhs/mceliece6960119/mceliece.go
new file mode 100644 (file)
index 0000000..eba3b34
--- /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.stargrave.org/vors/v5/pqhs/mceliece6960119/internal"
+       "go.stargrave.org/vors/v5/pqhs/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/pqhs/mceliece6960119/operations.go b/pqhs/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/pqhs/mceliece6960119/pk_gen.go b/pqhs/mceliece6960119/pk_gen.go
new file mode 100644 (file)
index 0000000..a505a8a
--- /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.stargrave.org/vors/v5/pqhs/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/pqhs/mceliece6960119/vec.go b/pqhs/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)
+}
diff --git a/pqhs/server.go b/pqhs/server.go
new file mode 100644 (file)
index 0000000..2c16506
--- /dev/null
@@ -0,0 +1,101 @@
+package pqhs
+
+import (
+       "crypto/ecdh"
+       "crypto/rand"
+
+       vors "go.stargrave.org/vors/v5/internal"
+       "go.stargrave.org/vors/v5/pqhs/mceliece6960119"
+       sntrup761kem "go.stargrave.org/vors/v5/pqhs/sntrup761/kem"
+       sntrup761 "go.stargrave.org/vors/v5/pqhs/sntrup761/kem/ntruprime/sntrup761"
+       "golang.org/x/crypto/chacha20poly1305"
+)
+
+type Server struct {
+       ephPrvSNTRUP sntrup761kem.PrivateKey
+       SymmetricState
+}
+
+func NewServer(
+       serverStaticPrvMcElieceRaw, serverStaticPrvX25519Raw,
+       serverStaticPubHash, clientPayload []byte,
+) (s *Server, payload []byte, err error) {
+       var serverStaticPrvMcEliece *mceliece6960119.PrivateKey
+       serverStaticPrvMcEliece, err = mceliece6960119.UnmarshalBinaryPrivateKey(
+               serverStaticPrvMcElieceRaw)
+       if err != nil {
+               return
+       }
+       x25519 := ecdh.X25519()
+       var serverStaticPrvX25519 *ecdh.PrivateKey
+       serverStaticPrvX25519, err = x25519.NewPrivateKey(serverStaticPrvX25519Raw)
+       if err != nil {
+               return
+       }
+       ctMcEliece := clientPayload[:mceliece6960119.CiphertextSize]
+       ctX25519 := clientPayload[mceliece6960119.CiphertextSize:]
+       var k []byte
+       k, err = mceliece6960119.Decapsulate(serverStaticPrvMcEliece, ctMcEliece)
+       if err != nil {
+               return
+       }
+       s = &Server{}
+       s.CK(k)
+       s.H([]byte(vors.Magic))
+       s.H(serverStaticPubHash)
+       s.H(ctMcEliece)
+       var clientEphPubX25519Raw []byte
+       clientEphPubX25519Raw, err = s.Open(CtxClientX25519, ctX25519)
+       if err != nil {
+               return
+       }
+       var clientEphPubX25519 *ecdh.PublicKey
+       clientEphPubX25519, k, err = DH(serverStaticPrvX25519, clientEphPubX25519Raw)
+       if err != nil {
+               return
+       }
+       s.CK(k)
+       var serverEphPrvX25519 *ecdh.PrivateKey
+       serverEphPrvX25519, err = x25519.GenerateKey(rand.Reader)
+       if err != nil {
+               return
+       }
+       ctX25519 = s.Seal(CtxServerX25519, serverEphPrvX25519.PublicKey().Bytes())
+       k, err = serverEphPrvX25519.ECDH(clientEphPubX25519)
+       if err != nil {
+               return
+       }
+       s.CK(k)
+       var serverEphPubSNTRUP sntrup761kem.PublicKey
+       serverEphPubSNTRUP, s.ephPrvSNTRUP, err = sntrup761.Scheme().GenerateKeyPair()
+       if err != nil {
+               return
+       }
+       var serverEphPubSNTRUPRaw []byte
+       serverEphPubSNTRUPRaw, err = serverEphPubSNTRUP.MarshalBinary()
+       if err != nil {
+               return
+       }
+       payload = append(ctX25519, s.Seal(CtxServerSNTRUP761, serverEphPubSNTRUPRaw)...)
+       return
+}
+
+func (s *Server) Read(reply []byte) (prefinish []byte, err error) {
+       sntrup761s := sntrup761.Scheme()
+       clientEphCTSNTRUPRaw := reply[:sntrup761s.CiphertextSize()+chacha20poly1305.Overhead]
+       prefinish = reply[len(clientEphCTSNTRUPRaw):]
+       {
+               clientEphCTSNTRUPRaw, err = s.Open(CtxClientSNTRUP761, clientEphCTSNTRUPRaw)
+               if err != nil {
+                       return
+               }
+               var k []byte
+               k, err = sntrup761s.Decapsulate(s.ephPrvSNTRUP, clientEphCTSNTRUPRaw)
+               if err != nil {
+                       return
+               }
+               s.CK(k)
+       }
+       prefinish, err = s.Open(CtxClientPrefinish, prefinish)
+       return
+}
diff --git a/pqhs/shake.go b/pqhs/shake.go
new file mode 100644 (file)
index 0000000..f0560fd
--- /dev/null
@@ -0,0 +1,39 @@
+package pqhs
+
+import (
+       "crypto/sha3"
+       "hash"
+       "io"
+)
+
+type SHAKE struct {
+       xof *sha3.SHAKE
+}
+
+func (h SHAKE) Size() int {
+       return 64
+}
+
+func (h SHAKE) BlockSize() int {
+       return h.xof.BlockSize()
+}
+
+func (h SHAKE) Reset() {
+       h.xof.Reset()
+}
+
+func (h SHAKE) Write(p []byte) (int, error) {
+       return h.xof.Write(p)
+}
+
+func (h SHAKE) Sum(b []byte) []byte {
+       buf := make([]byte, 64)
+       if _, err := io.ReadFull(h.xof, buf); err != nil {
+               panic(err)
+       }
+       return append(b, buf...)
+}
+
+func NewSHAKE256() hash.Hash {
+       return SHAKE{xof: sha3.NewSHAKE256()}
+}
diff --git a/pqhs/sntrup761/README b/pqhs/sntrup761/README
new file mode 100644 (file)
index 0000000..e7b08a2
--- /dev/null
@@ -0,0 +1,4 @@
+Go/Git is unable to fetch (https://github.com/cloudflare/circl)
+pull-request's commit (e8d7edb133624b7fa80e66fd9f6eb97f3f1cd361) to
+github.com/cloudflare/circl containing NTRU prime implementation
+(https://github.com/cloudflare/circl/pull/384). So copy it here.
diff --git a/pqhs/sntrup761/kem/kem.go b/pqhs/sntrup761/kem/kem.go
new file mode 100644 (file)
index 0000000..ede6fee
--- /dev/null
@@ -0,0 +1,118 @@
+// Package kem provides a unified interface for KEM schemes.
+//
+// A register of schemes is available in the package
+//
+//     github.com/cloudflare/circl/kem/schemes
+package kem
+
+import (
+       "encoding"
+       "errors"
+)
+
+// A KEM public key
+type PublicKey interface {
+       // Returns the scheme for this public key
+       Scheme() Scheme
+
+       encoding.BinaryMarshaler
+       Equal(PublicKey) bool
+}
+
+// A KEM private key
+type PrivateKey interface {
+       // Returns the scheme for this private key
+       Scheme() Scheme
+
+       encoding.BinaryMarshaler
+       Equal(PrivateKey) bool
+       Public() PublicKey
+}
+
+// A Scheme represents a specific instance of a KEM.
+type Scheme interface {
+       // Name of the scheme
+       Name() string
+
+       // GenerateKeyPair creates a new key pair.
+       GenerateKeyPair() (PublicKey, PrivateKey, error)
+
+       // Encapsulate generates a shared key ss for the public key and
+       // encapsulates it into a ciphertext ct.
+       Encapsulate(pk PublicKey) (ct, ss []byte, err error)
+
+       // Returns the shared key encapsulated in ciphertext ct for the
+       // private key sk.
+       Decapsulate(sk PrivateKey, ct []byte) ([]byte, error)
+
+       // Unmarshals a PublicKey from the provided buffer.
+       UnmarshalBinaryPublicKey([]byte) (PublicKey, error)
+
+       // Unmarshals a PrivateKey from the provided buffer.
+       UnmarshalBinaryPrivateKey([]byte) (PrivateKey, error)
+
+       // Size of encapsulated keys.
+       CiphertextSize() int
+
+       // Size of established shared keys.
+       SharedKeySize() int
+
+       // Size of packed private keys.
+       PrivateKeySize() int
+
+       // Size of packed public keys.
+       PublicKeySize() int
+
+       // DeriveKeyPair deterministicallly derives a pair of keys from a seed.
+       // Panics if the length of seed is not equal to the value returned by
+       // SeedSize.
+       DeriveKeyPair(seed []byte) (PublicKey, PrivateKey)
+
+       // Size of seed used in DeriveKey
+       SeedSize() int
+
+       // EncapsulateDeterministically generates a shared key ss for the public
+       // key deterministically from the given seed and encapsulates it into
+       // a ciphertext ct. If unsure, you're better off using Encapsulate().
+       EncapsulateDeterministically(pk PublicKey, seed []byte) (
+               ct, ss []byte, err error)
+
+       // Size of seed used in EncapsulateDeterministically().
+       EncapsulationSeedSize() int
+}
+
+// AuthScheme represents a KEM that supports authenticated key encapsulation.
+type AuthScheme interface {
+       Scheme
+       AuthEncapsulate(pkr PublicKey, sks PrivateKey) (ct, ss []byte, err error)
+       AuthEncapsulateDeterministically(pkr PublicKey, sks PrivateKey, seed []byte) (ct, ss []byte, err error)
+       AuthDecapsulate(skr PrivateKey, ct []byte, pks PublicKey) ([]byte, error)
+}
+
+var (
+       // ErrTypeMismatch is the error used if types of, for instance, private
+       // and public keys don't match
+       ErrTypeMismatch = errors.New("types mismatch")
+
+       // ErrSeedSize is the error used if the provided seed is of the wrong
+       // size.
+       ErrSeedSize = errors.New("wrong seed size")
+
+       // ErrPubKeySize is the error used if the provided public key is of
+       // the wrong size.
+       ErrPubKeySize = errors.New("wrong size for public key")
+
+       // ErrCiphertextSize is the error used if the provided ciphertext
+       // is of the wrong size.
+       ErrCiphertextSize = errors.New("wrong size for ciphertext")
+
+       // ErrPrivKeySize is the error used if the provided private key is of
+       // the wrong size.
+       ErrPrivKeySize = errors.New("wrong size for private key")
+
+       // ErrPubKey is the error used if the provided public key is invalid.
+       ErrPubKey = errors.New("invalid public key")
+
+       // ErrCipherText is the error used if the provided ciphertext is invalid.
+       ErrCipherText = errors.New("invalid ciphertext")
+)
diff --git a/pqhs/sntrup761/kem/ntruprime/doc.go b/pqhs/sntrup761/kem/ntruprime/doc.go
new file mode 100644 (file)
index 0000000..b55c96f
--- /dev/null
@@ -0,0 +1,10 @@
+//go:generate go run gen.go
+
+// Package ntruprime implements the NTRU Prime IND-CCA2 secure
+// key encapsulation mechanism (KEM) as submitted to round 3 of the NIST PQC
+// competition and described in
+//
+//     https://ntruprime.cr.yp.to/nist/ntruprime-20201007.pdf
+//
+// The code is translated from the C reference implementation.
+package ntruprime
diff --git a/pqhs/sntrup761/kem/ntruprime/internal/Decode.go b/pqhs/sntrup761/kem/ntruprime/internal/Decode.go
new file mode 100644 (file)
index 0000000..7d15e1b
--- /dev/null
@@ -0,0 +1,67 @@
+package internal
+
+// TO DO: Optimize the Decode function
+/* Decode(R,s,M,len) */
+/* assumes 0 < M[i] < 16384 */
+/* produces 0 <= R[i] < M[i] */
+func Decode(out []uint16, S []uint8, M []uint16, len int) {
+       index := 0
+       if len == 1 {
+               if M[0] == 1 {
+                       out[index] = 0
+               } else if M[0] <= 256 {
+                       out[index] = Uint32ModUint14(uint32(S[0]), M[0])
+               } else {
+                       out[index] = Uint32ModUint14(uint32(uint16(S[0])+((uint16(S[1]))<<8)), M[0])
+               }
+       }
+       if len > 1 {
+               R2 := make([]uint16, (len+1)/2)
+               M2 := make([]uint16, (len+1)/2)
+               bottomr := make([]uint16, len/2)
+               bottomt := make([]uint32, len/2)
+               i := 0
+               for i = 0; i < len-1; i += 2 {
+                       m := uint32(M[i]) * uint32(M[i+1])
+
+                       if m > 256*16383 {
+                               bottomt[i/2] = 256 * 256
+                               bottomr[i/2] = uint16(S[0]) + 256*uint16(S[1])
+                               S = S[2:]
+                               M2[i/2] = uint16((((m + 255) >> 8) + 255) >> 8)
+                       } else if m >= 16384 {
+                               bottomt[i/2] = 256
+                               bottomr[i/2] = uint16(S[0])
+                               S = S[1:]
+                               M2[i/2] = uint16((m + 255) >> 8)
+                       } else {
+                               bottomt[i/2] = 1
+                               bottomr[i/2] = 0
+                               M2[i/2] = uint16(m)
+                       }
+               }
+               if i < len {
+                       M2[i/2] = M[i]
+               }
+
+               Decode(R2, S, M2, (len+1)/2)
+
+               for i = 0; i < len-1; i += 2 {
+                       r := uint32(bottomr[i/2])
+                       var r1 uint32
+                       var r0 uint16
+
+                       r += bottomt[i/2] * uint32(R2[i/2])
+                       Uint32DivmodUint14(&r1, &r0, r, M[i])
+                       r1 = uint32(Uint32ModUint14(r1, M[i+1])) /* only needed for invalid inputs */
+
+                       out[index] = r0
+                       index++
+                       out[index] = uint16(r1)
+                       index++
+               }
+               if i < len {
+                       out[index] = R2[i/2]
+               }
+       }
+}
diff --git a/pqhs/sntrup761/kem/ntruprime/internal/Divmod.go b/pqhs/sntrup761/kem/ntruprime/internal/Divmod.go
new file mode 100644 (file)
index 0000000..f84cc43
--- /dev/null
@@ -0,0 +1,102 @@
+package internal
+
+/*
+CPU division instruction typically takes time depending on x.
+This software is designed to take time independent of x.
+Time still varies depending on m; user must ensure that m is constant.
+Time also varies on CPUs where multiplication is variable-time.
+There could be more CPU issues.
+There could also be compiler issues.
+*/
+// q, r = x/m
+// Returns quotient and remainder
+func Uint32DivmodUint14(q *uint32, r *uint16, x uint32, m uint16) {
+       var v uint32 = 0x80000000
+
+       v /= uint32(m)
+
+       *q = 0
+
+       qpart := uint32(uint64(x) * uint64(v) >> 31)
+
+       x -= qpart * uint32(m)
+       *q += qpart
+
+       qpart = uint32(uint64(x) * uint64(v) >> 31)
+       x -= qpart * uint32(m)
+       *q += qpart
+
+       x -= uint32(m)
+       *q += 1
+       mask := -(x >> 31)
+       x += mask & uint32(m)
+       *q += mask
+
+       *r = uint16(x)
+}
+
+// Returns the quotient of x/m
+func Uint32DivUint14(x uint32, m uint16) uint32 {
+       var q uint32
+       var r uint16
+       Uint32DivmodUint14(&q, &r, x, m)
+       return q
+}
+
+// Returns the remainder of x/m
+func Uint32ModUint14(x uint32, m uint16) uint16 {
+       var q uint32
+       var r uint16
+       Uint32DivmodUint14(&q, &r, x, m)
+       return r
+}
+
+// Calculates quotient and remainder
+func Int32DivmodUint14(q *int32, r *uint16, x int32, m uint16) {
+       var uq, uq2 uint32
+       var ur, ur2 uint16
+       var mask uint32
+
+       Uint32DivmodUint14(&uq, &ur, 0x80000000+uint32(x), m)
+       Uint32DivmodUint14(&uq2, &ur2, 0x80000000, m)
+
+       ur -= ur2
+       uq -= uq2
+       mask = -(uint32)(ur >> 15)
+       ur += uint16(mask & uint32(m))
+       uq += mask
+       *r = ur
+       *q = int32(uq)
+}
+
+// Returns quotient of x/m
+func Int32DivUint14(x int32, m uint16) int32 {
+       var q int32
+       var r uint16
+       Int32DivmodUint14(&q, &r, x, m)
+       return q
+}
+
+// Returns remainder of x/m
+func Int32ModUint14(x int32, m uint16) uint16 {
+       var q int32
+       var r uint16
+       Int32DivmodUint14(&q, &r, x, m)
+       return r
+}
+
+// Returns -1 if x!=0; else return 0
+func Int16NonzeroMask(x int16) int {
+       u := uint16(x) /* 0, else 1...65535 */
+       v := uint32(u) /* 0, else 1...65535 */
+       v = -v         /* 0, else 2^32-65535...2^32-1 */
+       v >>= 31       /* 0, else 1 */
+       return -int(v) /* 0, else -1 */
+}
+
+// Returns -1 if x<0; otherwise return 0
+func Int16NegativeMask(x int16) int {
+       u := uint16(x)
+       u >>= 15
+       return -(int)(u)
+}
diff --git a/pqhs/sntrup761/kem/ntruprime/internal/Encode.go b/pqhs/sntrup761/kem/ntruprime/internal/Encode.go
new file mode 100644 (file)
index 0000000..6c11fbd
--- /dev/null
@@ -0,0 +1,42 @@
+package internal
+
+/* 0 <= R[i] < M[i] < 16384 */
+func Encode(out []uint8, R, M []uint16, len int) {
+       if len > 1 {
+               R2 := make([]uint16, (len+1)/2)
+               M2 := make([]uint16, (len+1)/2)
+               var i int
+               for ; len > 1; len = (len + 1) / 2 {
+                       for i = 0; i < len-1; i += 2 {
+                               m0 := uint32(M[i])
+                               r := uint32(R[i]) + uint32(R[i+1])*m0
+                               m := uint32(M[i+1]) * m0
+                               for m >= 16384 {
+                                       out[0] = uint8(r)
+                                       out = out[1:]
+
+                                       r >>= 8
+                                       m = (m + 255) >> 8
+                               }
+                               R2[i/2] = uint16(r)
+                               M2[i/2] = uint16(m)
+                       }
+                       if i < len {
+                               R2[i/2] = R[i]
+                               M2[i/2] = M[i]
+                       }
+                       copy(R, R2)
+                       copy(M, M2)
+               }
+       }
+       if len == 1 {
+               r := R[0]
+               m := M[0]
+               for m > 1 {
+                       out[0] = uint8(r)
+                       out = out[1:]
+                       r >>= 8
+                       m = (m + 255) >> 8
+               }
+       }
+}
diff --git a/pqhs/sntrup761/kem/ntruprime/sntrup761/ntruprime.go b/pqhs/sntrup761/kem/ntruprime/sntrup761/ntruprime.go
new file mode 100644 (file)
index 0000000..b03c744
--- /dev/null
@@ -0,0 +1,971 @@
+// Code generated from sntrup.templ.go. DO NOT EDIT.
+
+// Package sntrup761 implements the IND-CCA2 secure key encapsulation mechanism
+// sntrup761 as submitted to round 3 of the NIST PQC competition and
+// described in
+//
+// https://ntruprime.cr.yp.to/nist/ntruprime-20201007.pdf
+package sntrup761
+
+import (
+       "bytes"
+       cryptoRand "crypto/rand"
+       "crypto/sha512"
+       "io"
+
+       "go.stargrave.org/vors/v5/pqhs/sntrup761/kem"
+       "go.stargrave.org/vors/v5/pqhs/sntrup761/kem/ntruprime/internal"
+       sntrupKem "go.stargrave.org/vors/v5/pqhs/sntrup761/pke/ntruprime/kem"
+       ntrup "go.stargrave.org/vors/v5/pqhs/sntrup761/pke/ntruprime/sntrup761"
+)
+
+type (
+       small  int8
+       Fq     int16
+       Inputs [p]small
+)
+
+const (
+       p            = ntrup.P
+       q            = ntrup.Q
+       q12          = ((q - 1) / 2)
+       roundedBytes = ntrup.RoundedBytes
+       rqBytes      = ntrup.RqBytes
+       w            = ntrup.W
+
+       hashBytes = 32
+
+       smallBytes = ((p + 3) / 4)
+
+       inputsBytes      = smallBytes
+       ciphertextsBytes = roundedBytes
+       secretKeysBytes  = (2 * smallBytes)
+       publicKeysBytes  = rqBytes
+
+       confirmBytes = 32
+)
+
+const (
+       // Size of seed for NewKeyFromSeed
+       // Note that during keyGen, a random small is generated until a valid one (whose reciprocal succeeds) is found
+       // The size of keySeed depends on the number of times the reciprocal fails
+       // This is why DeriveKeyPairFromGen is used to deterministically derive key pair instead of using seed
+       KeySeedSize = 4*p + p*4 + inputsBytes
+
+       // Size of seed for EncapsulateTo.
+       EncapsulationSeedSize = 4 * p
+
+       // Size of the established shared key.
+       SharedKeySize = ntrup.SharedKeySize
+
+       // Size of the encapsulated shared key.
+       CiphertextSize = ntrup.CiphertextSize
+
+       // Size of a packed public key.
+       PublicKeySize = ntrup.PublicKeySize
+
+       // Size of a packed private key.
+       PrivateKeySize = ntrup.PrivateKeySize
+)
+
+// Arithmetic operations over GF(3)
+
+// A polynomial of R has all of its coefficients in (-1,0,1)
+// F3 is always represented as -1,0,1
+// so ZZ_fromF3 is a no-op
+
+// x must not be close to top int16
+func f3Freeze(x int16) small {
+       return small(internal.Int32ModUint14(int32(x)+1, 3)) - 1
+}
+
+// Arithmetic operations over GF(q)
+
+/* always represented as -q12...q12 */
+/* so ZZ_fromFq is a no-op */
+
+/* x must not be close to top int32 */
+func fqFreeze(x int32) Fq {
+       return Fq(internal.Int32ModUint14(x+q12, q) - q12)
+}
+
+// Calculates reciprocal of Fq
+func fqRecip(a1 Fq) Fq {
+       var i int = 1
+       ai := a1
+
+       for i < (q - 2) {
+               ai = fqFreeze(int32(a1) * int32(ai))
+               i += 1
+       }
+       return ai
+}
+
+// Returns 0 if the weight w is equal to r
+// otherwise returns -1
+func weightwMask(r []small) int {
+       var weight int = 0
+
+       for i := 0; i < p; i++ {
+               weight += int(r[i]) & 1
+       }
+
+       // returns -1 if non zero
+       // otherwise returns 0 if weight==w
+       return internal.Int16NonzeroMask(int16(weight - w))
+
+}
+
+/* R3_fromR(R_fromRq(r)) */
+func r3FromRq(out []small, r []Fq) {
+       for i := 0; i < p; i++ {
+               out[i] = small(f3Freeze(int16(r[i])))
+       }
+}
+
+// h = f*g in the ring R3
+func r3Mult(h []small, f []small, g []small) {
+       fg := make([]small, p+p-1)
+       var result small
+       var i, j int
+
+       for i = 0; i < p; i++ {
+               result = 0
+               for j = 0; j <= i; j++ {
+                       result = f3Freeze(int16(result + f[j]*g[i-j]))
+               }
+               fg[i] = result
+       }
+
+       for i = p; i < p+p-1; i++ {
+               result = 0
+               for j = i - p + 1; j < p; j++ {
+                       result = f3Freeze(int16(result + f[j]*g[i-j]))
+               }
+               fg[i] = result
+       }
+
+       for i = p + p - 2; i >= p; i-- {
+               fg[i-p] = f3Freeze(int16(fg[i-p] + fg[i]))
+               fg[i-p+1] = f3Freeze(int16(fg[i-p+1] + fg[i]))
+       }
+
+       for i = 0; i < p; i++ {
+               h[i] = fg[i]
+       }
+}
+
+// Calculates the reciprocal of R3 polynomials
+// Returns 0 if recip succeeded; else -1
+func r3Recip(out []small, in []small) int {
+       // out := make([]small, p)
+       f := make([]small, p+1)
+       g := make([]small, p+1)
+       v := make([]small, p+1)
+       r := make([]small, p+1)
+
+       var sign int
+
+       r[0] = 1
+       f[0] = 1
+
+       f[p-1] = -1
+       f[p] = -1
+
+       for i := 0; i < p; i++ {
+               g[p-1-i] = in[i]
+       }
+
+       g[p] = 0
+
+       delta := 1
+
+       for loop := 0; loop < 2*p-1; loop++ {
+               for i := p; i > 0; i-- {
+                       v[i] = v[i-1]
+               }
+               v[0] = 0
+
+               sign = int(-g[0] * f[0])
+               var swap int = int(internal.Int16NegativeMask(int16(-delta)) & internal.Int16NonzeroMask(int16(g[0])))
+               delta ^= swap & int(delta^-delta)
+               delta += 1
+
+               for i := 0; i < p+1; i++ {
+                       t := swap & int(f[i]^g[i])
+                       f[i] ^= small(t)
+                       g[i] ^= small(t)
+                       t = swap & int(v[i]^r[i])
+                       v[i] ^= small(t)
+                       r[i] ^= small(t)
+               }
+               for i := 0; i < p+1; i++ {
+                       g[i] = f3Freeze(int16(int(g[i]) + sign*int(f[i])))
+               }
+
+               for i := 0; i < p+1; i++ {
+                       r[i] = f3Freeze(int16(int(r[i]) + sign*int(v[i])))
+               }
+
+               for i := 0; i < p; i++ {
+                       g[i] = g[i+1]
+               }
+
+               g[p] = 0
+
+       }
+       sign = int(f[0])
+
+       for i := 0; i < p; i++ {
+
+               out[i] = small(sign * int(v[p-1-i]))
+       }
+
+       return internal.Int16NonzeroMask(int16(delta))
+
+}
+
+// Polynomials mod q
+
+// h = f*g in the ring Rq */
+func rqMultSmall(h []Fq, f []Fq, g []small) {
+       fg := make([]Fq, p+p-1)
+       var result Fq
+
+       for i := 0; i < p; i++ {
+               result = 0
+               for j := 0; j <= i; j++ {
+                       result = fqFreeze(int32(result) + int32(f[j])*(int32)(g[i-j]))
+               }
+               fg[i] = result
+       }
+
+       for i := p; i < p+p-1; i++ {
+               result = 0
+               for j := i - p + 1; j < p; j++ {
+                       result = fqFreeze(int32(result) + int32(f[j])*(int32)(g[i-j]))
+               }
+               fg[i] = result
+       }
+
+       for i := p + p - 2; i >= p; i-- {
+               fg[i-p] = fqFreeze(int32(fg[i-p] + fg[i]))
+               fg[i-p+1] = fqFreeze(int32(fg[i-p+1] + fg[i]))
+
+       }
+
+       for i := 0; i < p; i++ {
+               h[i] = fg[i]
+       }
+}
+
+// h = 3f in Rq
+func rqMult3(h []Fq, f []Fq) {
+       for i := 0; i < p; i++ {
+               h[i] = fqFreeze(int32(3 * f[i]))
+       }
+}
+
+// Returns 0 if recip succeeded; else -1
+// out = 1/(3*in) in Rq
+func rqRecip3(out []Fq, in []small) int {
+       f := make([]Fq, p+1)
+       g := make([]Fq, p+1)
+       v := make([]Fq, p+1)
+       r := make([]Fq, p+1)
+
+       var swap, t int
+       var f0, g0 int32
+
+       r[0] = fqRecip(3)
+       f[0] = 1
+       f[p-1] = -1
+       f[p] = -1
+
+       for i := 0; i < p; i++ {
+               g[p-1-i] = Fq(in[i])
+       }
+       g[p] = 0
+
+       delta := 1
+
+       for loop := 0; loop < 2*p-1; loop++ {
+               for i := p; i > 0; i-- {
+                       v[i] = v[i-1]
+               }
+               v[0] = 0
+
+               swap = internal.Int16NegativeMask(int16(-delta)) & internal.Int16NonzeroMask(int16(g[0]))
+               delta ^= swap & (delta ^ -delta)
+               delta += 1
+
+               for i := 0; i < p+1; i++ {
+                       t = swap & int(f[i]^g[i])
+                       f[i] ^= Fq(t)
+                       g[i] ^= Fq(t)
+                       t = swap & int(v[i]^r[i])
+                       v[i] ^= Fq(t)
+                       r[i] ^= Fq(t)
+               }
+
+               f0 = int32(f[0])
+               g0 = int32(g[0])
+
+               for i := 0; i < p+1; i++ {
+                       g[i] = fqFreeze(f0*int32(g[i]) - g0*int32(f[i]))
+               }
+               for i := 0; i < p+1; i++ {
+                       r[i] = fqFreeze(f0*int32(r[i]) - g0*int32(v[i]))
+               }
+
+               for i := 0; i < p; i++ {
+                       g[i] = g[i+1]
+               }
+               g[p] = 0
+       }
+
+       scale := Fq(fqRecip(f[0]))
+       for i := 0; i < p; i++ {
+               out[i] = fqFreeze(int32(scale) * (int32)(v[p-1-i]))
+       }
+
+       return internal.Int16NonzeroMask(int16(delta))
+
+}
+
+// Rounding all coefficients of a polynomial to the nearest multiple of 3
+// Rounded polynomials mod q
+func round(out []Fq, a []Fq) {
+       for i := 0; i < p; i++ {
+               out[i] = a[i] - Fq(f3Freeze(int16(a[i])))
+       }
+}
+
+// Returns (min(x, y), max(x, y)), executes in constant time
+func minmax(x, y *uint32) {
+       var xi uint32 = *x
+       var yi uint32 = *y
+       var xy uint32 = xi ^ yi
+       var c uint32 = yi - xi
+       c ^= xy & (c ^ yi ^ 0x80000000)
+       c >>= 31
+       c = -c
+       c &= xy
+       *x = xi ^ c
+       *y = yi ^ c
+}
+
+// Sorts the array of unsigned integers
+func cryptoSortUint32(x []uint32, 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 {
+                               minmax(&x[i], &x[i+p])
+                       }
+               }
+               for q := top; q > p; q >>= 1 {
+                       for i := 0; i < n-q; i++ {
+                               if i&p == 0 {
+                                       minmax(&x[i+p], &x[i+q])
+                               }
+                       }
+               }
+       }
+}
+
+// Sorting to generate short polynomial
+func shortFromList(out []small, in []int32) {
+       L := make([]uint32, p)
+
+       var neg2, neg3 int = -2, -3
+
+       for i := 0; i < w; i++ {
+               L[i] = uint32(in[i]) & uint32((neg2))
+       }
+
+       for i := w; i < p; i++ {
+               L[i] = (uint32(in[i]) & uint32((neg3))) | 1
+       }
+
+       cryptoSortUint32(L, p)
+
+       for i := 0; i < p; i++ {
+               out[i] = small((L[i] & 3) - 1)
+       }
+}
+
+//  Underlying hash function
+
+// The input byte array, in, is prepended by the byte b
+// and its SHA-512 hash is calculated
+// Only the first 32 bytes of the hash are returned
+// e.g., b = 0 means out = Hash0(in)
+func hashPrefix(out []byte, b int, in []byte, inlen int) {
+       x := make([]byte, inlen+1)
+       h := make([]byte, 64)
+
+       x[0] = byte(b)
+       copy(x[1:], in)
+
+       hash := sha512.New()
+       hash.Write([]byte(x))
+       h = hash.Sum(nil)
+
+       copy(out, h[:32])
+
+}
+
+// Higher level randomness
+// Returns a random unsigned integer
+func urandom32(seed []byte) uint32 {
+       var out [4]uint32
+
+       out[0] = uint32(seed[0])
+       out[1] = uint32(seed[1]) << 8
+       out[2] = uint32(seed[2]) << 16
+       out[3] = uint32(seed[3]) << 24
+       return out[0] + out[1] + out[2] + out[3]
+}
+
+// Generates a random short polynomial
+func shortRandom(out []small, seed []byte) {
+
+       L := make([]uint32, p)
+
+       for i := 0; i < p; i++ {
+               L[i] = urandom32(seed[4*i : 4*i+4])
+       }
+
+       // Converts uint32 array to int32 array
+       L_int32 := make([]int32, p)
+       for i := 0; i < len(L); i++ {
+               L_int32[i] = int32(L[i])
+       }
+       shortFromList(out, L_int32)
+}
+
+// Generates a random list of small
+func smallRandom(out []small, seed []byte) {
+       for i := 0; i < p; i++ {
+               out[i] = small(((urandom32(seed[4*i:4*i+4])&0x3fffffff)*3)>>30) - 1
+       }
+}
+
+// Streamlined NTRU Prime Core
+
+// h,(f,ginv) = keyGen()
+func keyGen(h []Fq, f []small, ginv []small, gen *io.Reader) {
+       g := make([]small, p)
+       seed := make([]byte, 4*p+4*p)
+
+       if gen == nil {
+               for {
+                       cryptoRand.Read(seed[:4*p])
+                       smallRandom(g, seed[:4*p])
+                       if r3Recip(ginv, g) == 0 {
+                               break
+                       }
+               }
+               cryptoRand.Read(seed[4*p:])
+       } else {
+               for {
+                       for i := 0; i < p; i++ {
+                               (*gen).Read(seed[4*i : 4*i+4])
+                       }
+                       smallRandom(g, seed[:4*p])
+                       if r3Recip(ginv, g) == 0 {
+                               break
+                       }
+               }
+               for i := 0; i < p; i++ {
+                       (*gen).Read(seed[4*p+4*i : 4*p+4*i+4])
+               }
+       }
+       shortRandom(f, seed[4*p:])
+
+       finv := make([]Fq, p)
+
+       rqRecip3(finv, f) /* always works */
+       rqMultSmall(h, finv, g)
+}
+
+// c = encrypt(r,h)
+func encrypt(c []Fq, r []small, h []Fq) {
+       hr := make([]Fq, p)
+
+       rqMultSmall(hr, h, r)
+       round(c, hr)
+}
+
+// r = decrypt(c,(f,ginv))
+func decrypt(r []small, c []Fq, f []small, ginv []small) {
+       cf := make([]Fq, p)
+       cf3 := make([]Fq, p)
+       e := make([]small, p)
+       ev := make([]small, p)
+
+       rqMultSmall(cf, c, f)
+       rqMult3(cf3, cf)
+       r3FromRq(e, cf3)
+       r3Mult(ev, e, ginv)
+
+       mask := weightwMask(ev) /* 0 if weight w, else -1 */
+       for i := 0; i < w; i++ {
+               r[i] = ((ev[i] ^ 1) & small(^mask)) ^ 1
+       }
+
+       for i := w; i < p; i++ {
+               r[i] = ev[i] & small(^mask)
+       }
+}
+
+// Encoding small polynomials (including short polynomials)
+
+// Transform polynomial in R to bytes
+// these are the only functions that rely on p mod 4 = 1 */
+func smallEncode(s []byte, f []small) {
+       var x small
+       var index int = 0
+       for i := 0; i < p/4; i++ {
+               x = f[index] + 1
+               index++
+
+               x += (f[index] + 1) << 2
+               index++
+               x += (f[index] + 1) << 4
+               index++
+               x += (f[index] + 1) << 6
+               index++
+
+               s[0] = byte(x)
+               s = s[1:]
+       }
+       x = f[index] + 1
+
+       s[0] = byte(x)
+}
+
+// Transform bytes into polynomial in R
+func smallDecode(f []small, s []byte) {
+       var index int = 0
+       var x byte
+
+       for i := 0; i < p/4; i++ {
+               x = s[0]
+               s = s[1:]
+
+               f[index] = ((small)(x & 3)) - 1
+               x >>= 2
+               index++
+               f[index] = ((small)(x & 3)) - 1
+               x >>= 2
+               index++
+               f[index] = ((small)(x & 3)) - 1
+               x >>= 2
+               index++
+               f[index] = ((small)(x & 3)) - 1
+               index++
+       }
+       x = s[0]
+       f[index] = ((small)(x & 3)) - 1
+}
+
+// Encoding general polynomials
+
+// Transform polynomials in R/q to bytes
+func rqEncode(s []byte, r []Fq) {
+       R := make([]uint16, p)
+       M := make([]uint16, p)
+
+       for i := 0; i < p; i++ {
+               R[i] = uint16(r[i] + q12)
+               M[i] = q
+       }
+       internal.Encode(s, R, M, p)
+}
+
+// Transform polynomials in R/q from bytes
+func rqDecode(r []Fq, s []byte) {
+       R := make([]uint16, p)
+       M := make([]uint16, p)
+
+       for i := 0; i < p; i++ {
+               M[i] = q
+       }
+       internal.Decode(R, s, M, p)
+       for i := 0; i < p; i++ {
+               r[i] = ((Fq)(R[i])) - q12
+       }
+
+}
+
+// Encoding rounded polynomials
+
+// Transform rounded polynomials to bytes
+func roundedEncode(s []byte, r []Fq) {
+
+       R := make([]uint16, p)
+       M := make([]uint16, p)
+
+       for i := 0; i < p; i++ {
+               R[i] = uint16((int32((r[i])+q12) * 10923) >> 15)
+               M[i] = (q + 2) / 3
+       }
+       internal.Encode(s, R, M, p)
+}
+
+// Transform bytes to rounded polynomials
+func roundedDecode(r []Fq, s []byte) {
+       R := make([]uint16, p)
+       M := make([]uint16, p)
+
+       for i := 0; i < p; i++ {
+               M[i] = (q + 2) / 3
+       }
+       internal.Decode(R, s, M, p)
+       for i := 0; i < p; i++ {
+               r[i] = Fq(R[i]*3 - q12)
+       }
+
+}
+
+// Streamlined NTRU Prime Core plus encoding
+
+// Generates public key and private key
+// pk,sk = zKeyGen()
+func zKeyGen(pk []byte, sk []byte, gen *io.Reader) {
+
+       h := make([]Fq, p)
+       f := make([]small, p)
+       v := make([]small, p)
+       keyGen(h, f, v, gen)
+
+       rqEncode(pk, h)
+       smallEncode(sk, f)
+       sk = sk[smallBytes:]
+       smallEncode(sk, v)
+
+}
+
+// C = zEncrypt(r,pk)
+func zEncrypt(C []byte, r Inputs, pk []byte) {
+       h := make([]Fq, p)
+       c := make([]Fq, p)
+       rqDecode(h, pk)
+       encrypt(c, r[:], h)
+       roundedEncode(C, c)
+}
+
+// r = zDecrypt(C,sk)
+func zDecrypt(r *Inputs, C []byte, sk []byte) {
+       f := make([]small, p)
+       v := make([]small, p)
+       c := make([]Fq, p)
+
+       smallDecode(f, sk)
+       sk = sk[smallBytes:]
+       smallDecode(v, sk)
+       roundedDecode(c, C)
+
+       decrypt(r[:], c, f, v)
+}
+
+// Confirmation hash
+
+// h = hashConfirm(r,pk,cache); cache is Hash4(pk)
+func hashConfirm(h []byte, r []byte, pk []byte, cache []byte) {
+       x := make([]byte, hashBytes*2)
+
+       hashPrefix(x, 3, r, inputsBytes)
+
+       copy(x[hashBytes:], cache[:hashBytes])
+
+       hashPrefix(h, 2, x, len(x))
+
+}
+
+// Session-key hash
+
+// k = hashSession(b,y,z)
+func hashSession(k []byte, b int, y []byte, z []byte) {
+       x := make([]byte, hashBytes+ciphertextsBytes+confirmBytes)
+
+       hashPrefix(x, 3, y, inputsBytes)
+
+       copy(x[hashBytes:], z[:ciphertextsBytes+confirmBytes])
+
+       hashPrefix(k, b, x, len(x))
+
+}
+
+//  Streamlined NTRU Prime
+
+// pk,sk = kemKeyGen()
+func kemKeyGen(pk []byte, sk []byte, gen *io.Reader) {
+       zKeyGen(pk, sk, gen)
+       sk = sk[secretKeysBytes:]
+
+       copy(sk, pk)
+       sk = sk[publicKeysBytes:]
+
+       if gen != nil {
+               (*gen).Read(sk[:inputsBytes])
+
+       } else {
+               cryptoRand.Read(sk[:inputsBytes])
+       }
+       sk = sk[inputsBytes:]
+       hashPrefix(sk, 4, pk, publicKeysBytes)
+
+}
+
+// c,r_enc = hide(r,pk,cache); cache is Hash4(pk)
+func hide(c []byte, r_enc []byte, r Inputs, pk []byte, cache []byte) {
+       smallEncode(r_enc, r[:])
+       zEncrypt(c, r, pk)
+       c = c[ciphertextsBytes:]
+       hashConfirm(c, r_enc, pk, cache)
+
+}
+
+// Takes as input a public key
+// Returns ciphertext and shared key
+// c,k = encap(pk)
+func (pub PublicKey) EncapsulateTo(c []byte, k []byte, seed []byte) {
+       if seed == nil {
+               seed = make([]byte, 4*p)
+               cryptoRand.Read(seed)
+       }
+       if len(seed) != 4*p {
+               panic("seed must be of length EncapsulationSeedSize")
+       }
+       if len(c) != CiphertextSize {
+               panic("ct must be of length CiphertextSize")
+       }
+       if len(k) != SharedKeySize {
+               panic("ss must be of length SharedKeySize")
+       }
+
+       pk := pub.pk[:]
+
+       var r Inputs
+       r_enc := make([]byte, inputsBytes)
+       cache := make([]byte, hashBytes)
+
+       hashPrefix(cache, 4, pk, publicKeysBytes)
+       shortRandom(r[:], seed)
+       hide(c, r_enc, r, pk, cache)
+       hashSession(k, 1, r_enc, c)
+
+}
+
+// Returns 0 if matching ciphertext+confirm, else -1
+func ciphertexts_diff_mask(c []byte, c2 []byte) int {
+       var differentbits uint16 = 0
+       var len int = ciphertextsBytes + confirmBytes
+
+       for i := 0; i < len; i++ {
+               differentbits |= uint16((c[i]) ^ (c2[i]))
+       }
+       return int((1 & ((differentbits - 1) >> 8)) - 1)
+
+}
+
+// Returns shared key from ciphertext and private key
+// k = decap(c,sk)
+func (priv *PrivateKey) DecapsulateTo(k []byte, c []byte) {
+       if len(c) != CiphertextSize {
+               panic("ct must be of length CiphertextSize")
+       }
+
+       if len(k) != SharedKeySize {
+               panic("ss must be of length SharedKeySize")
+       }
+
+       sk := priv.sk[:]
+
+       pk := sk[secretKeysBytes:]
+       rho := pk[publicKeysBytes:]
+       cache := rho[inputsBytes:]
+       var r Inputs
+
+       r_enc := make([]byte, inputsBytes)
+       cnew := make([]byte, ciphertextsBytes+confirmBytes)
+
+       zDecrypt(&r, c, sk)
+       hide(cnew, r_enc, r, pk, cache)
+       var mask int = ciphertexts_diff_mask(c, cnew)
+
+       for i := 0; i < inputsBytes; i++ {
+               r_enc[i] ^= byte(mask & int(r_enc[i]^rho[i]))
+       }
+       hashSession(k, 1+mask, r_enc, c)
+}
+
+// The structure of the private key is given by the following segments:
+// The secret key, the public key, entropy and the hash of the public key
+type PrivateKey struct {
+       sk [PrivateKeySize]byte
+}
+
+type PublicKey struct {
+       pk [PublicKeySize]byte
+}
+
+type scheme struct{}
+
+var sch sntrupKem.Scheme = &scheme{}
+
+// Scheme returns a KEM interface.
+func Scheme() kem.Scheme { return sch }
+
+// SntrupScheme returns a sntrup.KEM interface
+func SntrupScheme() sntrupKem.Scheme { return sch }
+
+func (*scheme) Name() string               { return "sntrup761" }
+func (*scheme) PublicKeySize() int         { return PublicKeySize }
+func (*scheme) PrivateKeySize() int        { return PrivateKeySize }
+func (*scheme) SeedSize() int              { return KeySeedSize }
+func (*scheme) SharedKeySize() int         { return SharedKeySize }
+func (*scheme) CiphertextSize() int        { return CiphertextSize }
+func (*scheme) EncapsulationSeedSize() int { return EncapsulationSeedSize }
+
+func (sk *PrivateKey) Scheme() kem.Scheme { return sch }
+func (pk *PublicKey) Scheme() kem.Scheme  { return sch }
+
+func (sk *PrivateKey) MarshalBinary() ([]byte, error) {
+       var ret [PrivateKeySize]byte
+       copy(ret[:], sk.sk[:])
+       return ret[:], nil
+}
+
+func (sk *PrivateKey) Equal(other kem.PrivateKey) bool {
+       oth, ok := other.(*PrivateKey)
+       if !ok {
+               return false
+       }
+       return bytes.Equal(sk.sk[:], oth.sk[:])
+}
+
+func (pk *PublicKey) Equal(other kem.PublicKey) bool {
+       oth, ok := other.(*PublicKey)
+       if !ok {
+               return false
+       }
+       return bytes.Equal(pk.pk[:], oth.pk[:])
+}
+
+func (sk *PrivateKey) Public() kem.PublicKey {
+       var pk [PublicKeySize]byte
+       skey, _ := sk.MarshalBinary()
+       ppk := skey[secretKeysBytes : secretKeysBytes+publicKeysBytes]
+       copy(pk[:], ppk[:])
+       return &PublicKey{pk: pk}
+}
+
+func (pk *PublicKey) MarshalBinary() ([]byte, error) {
+       var ret [PublicKeySize]byte
+       copy(ret[:], pk.pk[:])
+       return ret[:], nil
+}
+
+func (*scheme) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
+       var pk [PublicKeySize]byte
+       var sk [PrivateKeySize]byte
+       kemKeyGen(pk[:], sk[:], nil)
+
+       return &PublicKey{pk: pk}, &PrivateKey{sk: sk}, nil
+
+}
+
+// Not used
+func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
+       return nil, nil
+}
+
+func (*scheme) DeriveKeyPairFromGen(gen *io.Reader) (kem.PublicKey, kem.PrivateKey) {
+
+       if gen == nil {
+               panic("A nist DRBG must be provided")
+       }
+
+       var pk [PublicKeySize]byte
+       var sk [PrivateKeySize]byte
+
+       kemKeyGen(pk[:], sk[:], gen)
+
+       return &PublicKey{pk: pk}, &PrivateKey{sk: sk}
+}
+
+func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) {
+       ct = make([]byte, CiphertextSize)
+       ss = make([]byte, SharedKeySize)
+
+       pub, ok := pk.(*PublicKey)
+       if !ok {
+               return nil, nil, kem.ErrTypeMismatch
+       }
+
+       pub.EncapsulateTo(ct, ss, nil)
+
+       return ct, ss, nil
+
+}
+
+func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) {
+
+       ct = make([]byte, CiphertextSize)
+       ss = make([]byte, SharedKeySize)
+
+       pub, ok := pk.(*PublicKey)
+       if !ok {
+               return nil, nil, kem.ErrTypeMismatch
+       }
+
+       pub.EncapsulateTo(ct, ss, seed)
+
+       return ct, ss, nil
+}
+
+func (*scheme) Decapsulate(sk kem.PrivateKey, ct []byte) ([]byte, error) {
+       ssk, ok := sk.(*PrivateKey)
+       if !ok {
+               return nil, kem.ErrTypeMismatch
+       }
+
+       if len(ct) != CiphertextSize {
+               return nil, kem.ErrCiphertextSize
+       }
+       ss := [SharedKeySize]byte{}
+
+       ssk.DecapsulateTo(ss[:], ct)
+
+       return ss[:], nil
+}
+
+func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (kem.PublicKey, error) {
+       if len(buf) != PublicKeySize {
+               return nil, kem.ErrPubKeySize
+       }
+       pk := [PublicKeySize]byte{}
+       copy(pk[:], buf)
+       return &PublicKey{pk: pk}, nil
+}
+
+func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (kem.PrivateKey, error) {
+       if len(buf) != PrivateKeySize {
+               return nil, kem.ErrPrivKeySize
+       }
+       sk := [PrivateKeySize]byte{}
+       copy(sk[:], buf)
+       return &PrivateKey{sk: sk}, nil
+}
diff --git a/pqhs/sntrup761/pke/ntruprime/kem/kem.go b/pqhs/sntrup761/pke/ntruprime/kem/kem.go
new file mode 100644 (file)
index 0000000..2b6309a
--- /dev/null
@@ -0,0 +1,17 @@
+// Package kem provides a unified interface for Streamlined NTRU Prime KEM schemes.
+package kem
+
+import (
+       "io"
+
+       "go.stargrave.org/vors/v5/pqhs/sntrup761/kem"
+)
+
+// A Scheme represents a specific instance of a NTRU PRIME KEM.
+type Scheme interface {
+       kem.Scheme
+
+       // DeriveKeyPairFromGen deterministicallly derives a pair of keys from a nist DRBG.
+       // Only used for deterministic testing
+       DeriveKeyPairFromGen(gen *io.Reader) (kem.PublicKey, kem.PrivateKey)
+}
diff --git a/pqhs/sntrup761/pke/ntruprime/kem/schemes/sntrup/schemes.go b/pqhs/sntrup761/pke/ntruprime/kem/schemes/sntrup/schemes.go
new file mode 100644 (file)
index 0000000..b0b411a
--- /dev/null
@@ -0,0 +1,39 @@
+// Package schemes contains a register of Streamlined NTRU Prime KEM schemes.
+//
+// # Schemes Implemented
+//
+// Post-quantum kems:
+//
+//     SNTRUP653, SNTRUP761, SNTRUP857, SNTRUP953, SNTRUP1013, SNTRUP1277
+package sntrupSchemes
+
+import (
+       "strings"
+
+       "go.stargrave.org/vors/v5/pqhs/sntrup761/kem/ntruprime/sntrup761"
+       "go.stargrave.org/vors/v5/pqhs/sntrup761/pke/ntruprime/kem"
+)
+
+var allSchemes = [...]kem.Scheme{
+       sntrup761.SntrupScheme(),
+}
+
+var allSchemeNames map[string]kem.Scheme
+
+func init() {
+       allSchemeNames = make(map[string]kem.Scheme)
+       for _, scheme := range allSchemes {
+               allSchemeNames[strings.ToLower(scheme.Name())] = scheme
+       }
+}
+
+// ByName returns the scheme with the given name and nil if it is not
+// supported.
+//
+// Names are case insensitive.
+func ByName(name string) kem.Scheme {
+       return allSchemeNames[strings.ToLower(name)]
+}
+
+// All returns all KEM schemes supported.
+func All() []kem.Scheme { a := allSchemes; return a[:] }
diff --git a/pqhs/sntrup761/pke/ntruprime/sntrup761/params.go b/pqhs/sntrup761/pke/ntruprime/sntrup761/params.go
new file mode 100644 (file)
index 0000000..4e01822
--- /dev/null
@@ -0,0 +1,25 @@
+// Code generated from sntrup.params.templ.go. DO NOT EDIT.
+package ntruprime
+
+const (
+       P            = 761
+       Q            = 4591
+       RoundedBytes = 1007
+       RqBytes      = 1158
+       W            = 286
+)
+
+const (
+
+       // Size of the established shared key.
+       SharedKeySize = 32
+
+       // Size of the encapsulated shared key.
+       CiphertextSize = 1039
+
+       // Size of a packed public key.
+       PublicKeySize = 1158
+
+       // Size of a packed private key.
+       PrivateKeySize = 1763
+)
diff --git a/pqhs/state.go b/pqhs/state.go
new file mode 100644 (file)
index 0000000..35cbe65
--- /dev/null
@@ -0,0 +1,64 @@
+package pqhs
+
+import (
+       "crypto/cipher"
+       "crypto/hkdf"
+       "crypto/sha3"
+
+       "golang.org/x/crypto/chacha20poly1305"
+)
+
+type SymmetricState struct {
+       h, ck []byte
+}
+
+func (state *SymmetricState) K(ctx string) []byte {
+       k, err := hkdf.Expand(NewSHAKE256, state.ck, ctx, chacha20poly1305.KeySize)
+       if err != nil {
+               panic(err)
+       }
+       return k
+}
+
+func (state *SymmetricState) H(data []byte) {
+       state.h = sha3.SumSHAKE256(append(state.h, data...), 64)
+}
+
+func (state *SymmetricState) CK(key []byte) {
+       var err error
+       state.ck, err = hkdf.Extract(NewSHAKE256, key, state.ck)
+       if err != nil {
+               panic(err)
+       }
+}
+
+func (state *SymmetricState) Seal(ctx string, data []byte) []byte {
+       aead, err := chacha20poly1305.New(state.K(ctx))
+       if err != nil {
+               panic(err)
+       }
+       ct := aead.Seal(nil, make([]byte, aead.NonceSize()), data, state.h)
+       state.H(ct)
+       return ct
+}
+
+func (state *SymmetricState) Open(ctx string, ct []byte) (pt []byte, err error) {
+       var aead cipher.AEAD
+       aead, err = chacha20poly1305.New(state.K(ctx))
+       if err != nil {
+               panic(err)
+       }
+       pt, err = aead.Open(nil, make([]byte, aead.NonceSize()), ct, state.h)
+       if err == nil {
+               state.H(ct)
+       }
+       return
+}
+
+func (state *SymmetricState) Binding(l int) []byte {
+       binding, err := hkdf.Expand(NewSHAKE256, state.ck, string(state.h), l)
+       if err != nil {
+               panic(err)
+       }
+       return binding
+}