diff --git a/kem/mceliece/gen.go b/kem/mceliece/gen.go new file mode 100644 index 000000000..440d34c08 --- /dev/null +++ b/kem/mceliece/gen.go @@ -0,0 +1,162 @@ +//go:build ignore +// +build ignore + +// Autogenerates wrappers from templates to prevent too much duplicated code +// between the code for different modes. +package main + +import ( + "bytes" + "go/format" + "io/ioutil" + "strings" + "text/template" +) + +type Param struct { + Gf string + PublicKeySize uint + PrivateKeySize uint + CiphertextSize uint + SysN uint + SysT uint +} + +type Instance struct { + Name string + Param Param +} + +func (m Instance) Pkg() string { + return strings.ToLower(m.Name) +} + +func (m Instance) IsSemiSystematic() bool { + return strings.HasSuffix(m.Name, "f") +} + +func (m Instance) Is348864() bool { + return strings.Contains(m.Name, "348864") +} + +func (m Instance) Is460896() bool { + return strings.Contains(m.Name, "460896") +} + +func (m Instance) Is6688128() bool { + return strings.Contains(m.Name, "6688128") +} + +func (m Instance) Is6960119() bool { + return strings.Contains(m.Name, "6960119") +} + +func (m Instance) Is8192128() bool { + return strings.Contains(m.Name, "8192128") +} + +var ( + McElieceParam348864 = Param{ + Gf: "gf2e12", + PublicKeySize: 261120, + PrivateKeySize: 6492, + CiphertextSize: 96, + SysN: 3488, + SysT: 64, + } + McElieceParam460896 = Param{ + Gf: "gf2e13", + PublicKeySize: 524160, + PrivateKeySize: 13608, + CiphertextSize: 156, + SysN: 4608, + SysT: 96, + } + McElieceParam6688128 = Param{ + Gf: "gf2e13", + PublicKeySize: 1044992, + PrivateKeySize: 13932, + CiphertextSize: 208, + SysN: 6688, + SysT: 128, + } + McElieceParam6960119 = Param{ + Gf: "gf2e13", + PublicKeySize: 1047319, + PrivateKeySize: 13948, + CiphertextSize: 194, + SysN: 6960, + SysT: 119, + } + McElieceParam8192128 = Param{ + Gf: "gf2e13", + PublicKeySize: 1357824, + PrivateKeySize: 14120, + CiphertextSize: 208, + SysN: 8192, + SysT: 128, + } + Instances = []Instance{ + {Name: "mceliece348864", Param: McElieceParam348864}, + {Name: "mceliece348864f", Param: McElieceParam348864}, + {Name: "mceliece460896", Param: McElieceParam460896}, + {Name: "mceliece460896f", Param: McElieceParam460896}, + {Name: "mceliece6688128", Param: McElieceParam6688128}, + {Name: "mceliece6688128f", Param: McElieceParam6688128}, + {Name: "mceliece6960119", Param: McElieceParam6960119}, + {Name: "mceliece6960119f", Param: McElieceParam6960119}, + {Name: "mceliece8192128", Param: McElieceParam8192128}, + {Name: "mceliece8192128f", Param: McElieceParam8192128}, + } + + TemplateWarning = "// Code generated from" +) + +func main() { + generateTemplateFilesIf("templates/benes_348864.templ.go", "benes", func(m Instance) bool { return m.Is348864() }) + generateTemplateFilesIf("templates/benes_other.templ.go", "benes", func(m Instance) bool { return !m.Is348864() }) + generateTemplateFilesIf("templates/operations_6960119.templ.go", "operations", func(m Instance) bool { return m.Is6960119() }) + generateTemplateFiles("templates/mceliece.templ.go", "mceliece") + generateTemplateFiles("templates/pk_gen_vec.templ.go", "pk_gen") + generateTemplateFiles("templates/vec.templ.go", "vec") + generateTemplateFilesIf("templates/fft_348864.templ.go", "fft", func(m Instance) bool { return m.Is348864() }) + generateTemplateFilesIf("templates/fft_other.templ.go", "fft", func(m Instance) bool { return !m.Is348864() }) +} + +func generateTemplateFiles(templatePath, outputName string) { + generateTemplateFilesIf(templatePath, outputName, func(instance Instance) bool { return true }) +} + +func generateTemplateFilesIf(templatePath, outputName string, predicate func(Instance) bool) { + tl, err := template.ParseFiles(templatePath) + if err != nil { + panic(err) + } + + for _, mode := range Instances { + if !predicate(mode) { + continue + } + buf := new(bytes.Buffer) + err := tl.Execute(buf, mode) + if err != nil { + panic(err) + } + + // Formating output code + code, err := format.Source(buf.Bytes()) + if err != nil { + panic("error formating code") + } + + res := string(code) + offset := strings.Index(res, TemplateWarning) + if offset == -1 { + panic("Missing template warning in pkg.templ.go") + } + err = ioutil.WriteFile(mode.Pkg()+"/"+outputName+".go", []byte(res[offset:]), 0o644) + if err != nil { + panic(err) + } + } +} diff --git a/kem/mceliece/internal/controlbits.go b/kem/mceliece/internal/controlbits.go new file mode 100644 index 000000000..45773e48f --- /dev/null +++ b/kem/mceliece/internal/controlbits.go @@ -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/kem/mceliece/internal/controlbits_test.go b/kem/mceliece/internal/controlbits_test.go new file mode 100644 index 000000000..2345ef43d --- /dev/null +++ b/kem/mceliece/internal/controlbits_test.go @@ -0,0 +1,125 @@ +package internal + +import ( + "reflect" + "testing" + + "github.com/cloudflare/circl/internal/test" + "github.com/cloudflare/circl/kem/mceliece/testdata" +) + +const testPath = "../testdata/testdata.txt.bz2" + +func TestLayer1(t *testing.T) { + N := 4 + S := 1 + p := []int16{0, 3, 7, 11} + cb := []byte{63} + test.CheckOk(len(p) == N, "length does not match", t) + layer(p, cb, S, N) + pRef := []int16{7, 11, 0, 3} + if !reflect.DeepEqual(pRef, p) { + test.ReportError(t, p, pRef) + } +} + +func TestLayer2(t *testing.T) { + N := 8 + S := 2 + p := []int16{0, 3, 7, 11, 13, 17, 23, 0} + cb := []byte{0xAA, 0xFF, 0x02} + test.CheckOk(len(p) == N, "length does not match", t) + layer(p, cb, S, N) + pRef := []int16{0, 17, 7, 0, 13, 3, 23, 11} + if !reflect.DeepEqual(pRef, p) { + test.ReportError(t, p, pRef) + } +} + +func TestRecursion1(t *testing.T) { + const ( + W = 3 + N = 1 << W + STEP = 1 + POS = 0 + ) + pi := []int16{0, 2, 4, 6, 1, 3, 5, 7} + temp := [2 * N]int32{} + out := [3]byte{} + cbRecursion(out[:], POS, STEP, pi, W, N, temp[:]) + outRef := [3]byte{0xCA, 0x66, 0x0C} + if !reflect.DeepEqual(outRef, out) { + test.ReportError(t, out, outRef) + } +} + +func TestRecursion2(t *testing.T) { + const ( + W = 3 + N = 1 << W + STEP = 2 + POS = 0 + ) + pi := []int16{0, 2, 4, 6, 1, 3, 5, 7} + temp := [2 * N]int32{} + out := [5]byte{} + cbRecursion(out[:], POS, STEP, pi, W, N, temp[:]) + outRef := [5]byte{0x44, 0x50, 0x14, 0x14, 0x50} + if !reflect.DeepEqual(outRef, out) { + test.ReportError(t, out, outRef) + } +} + +func TestControlBitsFromPermutationKat3Mceliece348864(t *testing.T) { + pi, err := testdata.FindTestDataI16("controlbits_kat3_mceliece348864_pi", testPath) + if err != nil { + t.Errorf(err.Error()) + return + } + want, err := testdata.FindTestDataByte("controlbits_kat3_mceliece348864_out_ref", testPath) + if err != nil { + t.Errorf(err.Error()) + return + } + out := make([]byte, 5888) + ControlBitsFromPermutation(out, pi, 12, 4096) + if !reflect.DeepEqual(out, want) { + test.ReportError(t, out, want) + } +} + +func TestControlBitsFromPermutationKat8Mceliece348864(t *testing.T) { + pi, err := testdata.FindTestDataI16("controlbits_kat8_mceliece348864_pi", testPath) + if err != nil { + t.Errorf(err.Error()) + return + } + want, err := testdata.FindTestDataByte("controlbits_kat8_mceliece348864_out_ref", testPath) + if err != nil { + t.Errorf(err.Error()) + return + } + out := make([]byte, 5888) + ControlBitsFromPermutation(out, pi, 12, 4096) + if !reflect.DeepEqual(out, want) { + test.ReportError(t, out, want) + } +} + +func TestControlBitsFromPermutationKat9Mceliece348864(t *testing.T) { + pi, err := testdata.FindTestDataI16("controlbits_kat9_mceliece348864_pi", testPath) + if err != nil { + t.Errorf(err.Error()) + return + } + want, err := testdata.FindTestDataByte("controlbits_kat9_mceliece348864_out_ref", testPath) + if err != nil { + t.Errorf(err.Error()) + return + } + out := make([]byte, 5888) + ControlBitsFromPermutation(out, pi, 12, 4096) + if !reflect.DeepEqual(out, want) { + test.ReportError(t, out, want) + } +} diff --git a/kem/mceliece/internal/djbsort.go b/kem/mceliece/internal/djbsort.go new file mode 100644 index 000000000..9f49def14 --- /dev/null +++ b/kem/mceliece/internal/djbsort.go @@ -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/kem/mceliece/internal/djbsort_test.go b/kem/mceliece/internal/djbsort_test.go new file mode 100644 index 000000000..5e47f27ff --- /dev/null +++ b/kem/mceliece/internal/djbsort_test.go @@ -0,0 +1,70 @@ +package internal + +import ( + "math/rand" + "sort" + "testing" + + "github.com/cloudflare/circl/internal/test" +) + +type ( + foo []int32 + bar []uint64 +) + +//nolint:gosec +func TestSortInt32(t *testing.T) { + arr := make(foo, 314) + for i := 0; i < len(arr); i++ { + arr[i] = rand.Int31() + } + + int32Sort(arr, int32(len(arr))) + if !sort.IsSorted(arr) { + want := make(foo, len(arr)) + copy(want, arr) + sort.Sort(want) + test.ReportError(t, arr, want) + } +} + +//nolint:gosec +func TestSortUInt64(t *testing.T) { + arr := make(bar, 314) + for i := 0; i < len(arr); i++ { + arr[i] = rand.Uint64() + } + + UInt64Sort(arr, len(arr)) + if !sort.IsSorted(arr) { + want := make(bar, len(arr)) + copy(want, arr) + sort.Sort(want) + test.ReportError(t, arr, want) + } +} + +func (f foo) Len() int { + return len(f) +} + +func (f foo) Less(i, j int) bool { + return f[i] < f[j] +} + +func (f foo) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + +func (f bar) Len() int { + return len(f) +} + +func (f bar) Less(i, j int) bool { + return f[i] < f[j] +} + +func (f bar) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} diff --git a/kem/mceliece/internal/fft_const.go b/kem/mceliece/internal/fft_const.go new file mode 100644 index 000000000..7e629f086 --- /dev/null +++ b/kem/mceliece/internal/fft_const.go @@ -0,0 +1,3096 @@ +package internal + +import ( + "github.com/cloudflare/circl/math/gf2e12" + "github.com/cloudflare/circl/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/kem/mceliece/internal/powers.go b/kem/mceliece/internal/powers.go new file mode 100644 index 000000000..3f048796d --- /dev/null +++ b/kem/mceliece/internal/powers.go @@ -0,0 +1,2828 @@ +package internal + +import ( + "github.com/cloudflare/circl/math/gf2e12" + "github.com/cloudflare/circl/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/kem/mceliece/kat_test.go b/kem/mceliece/kat_test.go new file mode 100644 index 000000000..81ad3dd8d --- /dev/null +++ b/kem/mceliece/kat_test.go @@ -0,0 +1,88 @@ +package mceliece + +// Code to generate the NIST "PQCsignKAT" test vectors. +// See PQCsignKAT_sign.c and randombytes.c in the reference implementation. + +import ( + "bytes" + "crypto/sha256" + "fmt" + "testing" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/test" + "github.com/cloudflare/circl/kem/schemes" +) + +func TestPQCgenKATKem(t *testing.T) { + kats := []struct { + name string + want string + }{ + // Computed from reference implementation + {"mceliece348864f", "d0d5ea348a181740862dcc8476ff7d00ce44d1c6e36b2145289d97f580f2cd7d"}, + {"mceliece348864", "76351ed2e95a616ca76230bac579cead21012d89181c7398381d0bbe904ab92c"}, + {"mceliece460896f", "552da50baff2666db7b64486c88da4e2b65b25c3d5424be682ca08ffce15a356"}, + {"mceliece460896", "fd785edfe1b721fb24fe159cb9f30cc17daec3d188d59a4bf47a83388880192e"}, + {"mceliece6688128f", "7b64c9882a00bc984e0ca9d3748d0b1bd9215d1bcf921643ee88d28d539303d8"}, + {"mceliece6688128", "3f926328959729c61a11b11ab6326246a42d9b3e76943bba2625342ea33723e2"}, + {"mceliece6960119f", "d6d3e929ff505108fd545d14df5f5bac234cd6d882f0eed3fd628f122e3093c6"}, + {"mceliece6960119", "e4d608fa9795c1a1704709ab9df3940ae1dbf0f708cc0dbdf76c8f3173088e46"}, + {"mceliece8192128f", "3fdb40d47705829c16de4fb5a81f7c095eb4dadc306cfc2c89eff2f483c42402"}, + {"mceliece8192128", "beb28fc0d1555a0028afeb6ebc72b8337f424a826be3d49b47759b8bda50db90"}, + } + + for _, kat := range kats { + kat := kat + t.Run(kat.name, func(t *testing.T) { + testPQCgenKATKem(t, kat.name, kat.want) + }) + } +} + +func testPQCgenKATKem(t *testing.T, name, expected string) { + scheme := schemes.ByName(name) + if scheme == nil { + t.Fatal() + } + + var seed [48]byte + kseed := make([]byte, scheme.SeedSize()) + for i := 0; i < 48; i++ { + seed[i] = byte(i) + } + f := sha256.New() + g := nist.NewDRBG(&seed) + fmt.Fprintf(f, "# kem/%s\n\n", name) + for i := 0; i < 10; i++ { + g.Fill(seed[:]) + fmt.Fprintf(f, "count = %d\n", i) + fmt.Fprintf(f, "seed = %X\n", seed) + + g2 := nist.NewDRBG(&seed) + + g2.Fill(kseed) + + pk, sk := scheme.DeriveKeyPair(kseed) + ppk, _ := pk.MarshalBinary() + psk, _ := sk.MarshalBinary() + ct, ss, err := scheme.EncapsulateDeterministically(pk, seed[:]) + if err != nil { + t.Fatal(err) + } + ss2, err := scheme.Decapsulate(sk, ct) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(ss, ss2) { + test.ReportError(t, fmt.Sprintf("%X", ss2), fmt.Sprintf("%X", ss)) + } + fmt.Fprintf(f, "pk = %X\n", ppk) + fmt.Fprintf(f, "sk = %X\n", psk) + fmt.Fprintf(f, "ct = %X\n", ct) + fmt.Fprintf(f, "ss = %X\n\n", ss) + } + if fmt.Sprintf("%x", f.Sum(nil)) != expected { + t.Fatal() + } +} diff --git a/kem/mceliece/mceliece348864/benes.go b/kem/mceliece/mceliece348864/benes.go new file mode 100644 index 000000000..a72040b03 --- /dev/null +++ b/kem/mceliece/mceliece348864/benes.go @@ -0,0 +1,71 @@ +// Code generated from benes_348864.templ.go. DO NOT EDIT. + +package mceliece348864 + +// Layers of the Beneš network. The required size of `data` and `bits` depends on the value `lgs`. +func layer(data, bits []uint64, lgs int) { + index := 0 + s := 1 << lgs + for i := 0; i < 64; i += s * 2 { + for j := i; j < i+s; j++ { + d := data[j] ^ data[j+s] + d &= bits[index] + index++ + data[j] ^= d + data[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 *[512]byte, bits *[condBytes]byte) { + bs := [64]uint64{} + cond := [64]uint64{} + for i := 0; i < 64; i++ { + bs[i] = load8(r[i*8:]) + } + + transpose64x64(&bs, &bs) + + for low := 0; low <= 5; low++ { + for i := 0; i < 64; i++ { + cond[i] = uint64(load4(bits[low*256+i*4:])) + } + transpose64x64(&cond, &cond) + layer(bs[:], cond[:], low) + } + + transpose64x64(&bs, &bs) + + for low := 0; low <= 5; low++ { + for i := 0; i < 32; i++ { + cond[i] = load8(bits[(low+6)*256+i*8:]) + } + layer(bs[:], cond[:], low) + } + for low := 4; low >= 0; low-- { + for i := 0; i < 32; i++ { + cond[i] = load8(bits[(4-low+6+6)*256+i*8:]) + } + layer(bs[:], cond[:], low) + } + + transpose64x64(&bs, &bs) + + for low := 5; low >= 0; low-- { + for i := 0; i < 64; i++ { + cond[i] = uint64(load4(bits[(5-low+6+6+5)*256+i*4:])) + } + transpose64x64(&cond, &cond) + layer(bs[:], cond[:], low) + } + transpose64x64(&bs, &bs) + + for i := 0; i < 64; i++ { + store8(r[i*8:], bs[i]) + } +} diff --git a/kem/mceliece/mceliece348864/benes_test.go b/kem/mceliece/mceliece348864/benes_test.go new file mode 100644 index 000000000..c095eade3 --- /dev/null +++ b/kem/mceliece/mceliece348864/benes_test.go @@ -0,0 +1,76 @@ +package mceliece348864 + +import ( + "fmt" + "reflect" + "testing" + + "github.com/cloudflare/circl/internal/test" + "github.com/cloudflare/circl/kem/mceliece/testdata" +) + +const testPath = "../testdata/testdata.txt.bz2" + +func TestLayer(t *testing.T) { + data := [64]uint64{} + bits := [32]uint64{} + for i := 0; i < len(data); i++ { + data[i] = 0xAAAA ^ (uint64(i) * 17) + } + for i := 0; i < len(bits); i++ { + bits[i] = uint64(i) << 3 + } + layer(data[:], bits[:], 4) + want := [64]uint64{ + 0xAAAA, 0xAABB, 0xAA98, 0xAA89, 0xAAEE, 0xAADF, 0xAADC, 0xAAED, 0xAA22, 0xAA33, + 0xAA10, 0xAA41, 0xAA66, 0xAA57, 0xAA54, 0xAA25, 0xABBA, 0xAB8B, 0xAB88, 0xABF9, + 0xABFE, 0xABEF, 0xABCC, 0xAB1D, 0xAB32, 0xAB03, 0xAB00, 0xAB31, 0xAB76, 0xAB67, + 0xAB44, 0xA8D5, 0xA88A, 0xA89B, 0xA8F8, 0xA8E9, 0xA8CE, 0xA87F, 0xA83C, 0xA80D, + 0xA802, 0xA853, 0xA870, 0xA861, 0xA846, 0xA8B7, 0xA9B4, 0xA985, 0xA99A, 0xA9EB, + 0xA9E8, 0xA9D9, 0xA9DE, 0xA98F, 0xA92C, 0xA93D, 0xA912, 0xA923, 0xA960, 0xA951, + 0xA956, 0xAE47, 0xAEA4, 0xAEB5, + } + if !reflect.DeepEqual(data, want) { + test.ReportError(t, fmt.Sprintf("%X", data), fmt.Sprintf("%X", want)) + } +} + +func TestLayer2(t *testing.T) { + data, err := testdata.FindTestDataU64("mceliece348864_benes_layer_data_before", testPath) + if err != nil { + t.Fatal(err) + } + bits, err := testdata.FindTestDataU64("mceliece348864_benes_layer_bits", testPath) + if err != nil { + t.Fatal(err) + } + want, err := testdata.FindTestDataU64("mceliece348864_benes_layer_data_after", testPath) + if err != nil { + t.Fatal(err) + } + + layer(data, bits, 0) + if !reflect.DeepEqual(data, want) { + test.ReportError(t, fmt.Sprintf("%X", data), fmt.Sprintf("%X", want)) + } +} + +func TestApplyBenes(t *testing.T) { + r, err := testdata.FindTestDataByte("mceliece348864_benes_apply_benes_r_before", testPath) + if err != nil { + t.Fatal(err) + } + bits, err := testdata.FindTestDataByte("mceliece348864_benes_apply_benes_bits", testPath) + if err != nil { + t.Fatal(err) + } + want, err := testdata.FindTestDataByte("mceliece348864_benes_apply_benes_r_after", testPath) + if err != nil { + t.Fatal(err) + } + + applyBenes((*[512]byte)(r), (*[5888]byte)(bits)) + if !reflect.DeepEqual(r[:], want) { + test.ReportError(t, fmt.Sprintf("%X", r), fmt.Sprintf("%X", want)) + } +} diff --git a/kem/mceliece/mceliece348864/fft.go b/kem/mceliece/mceliece348864/fft.go new file mode 100644 index 000000000..4099eb723 --- /dev/null +++ b/kem/mceliece/mceliece348864/fft.go @@ -0,0 +1,65 @@ +// Code generated from fft_348864.templ.go. DO NOT EDIT. + +// The following code is translated from the C `vec` Additional Implementation +// from the NIST round 4 submission package. + +package mceliece348864 + +import "github.com/cloudflare/circl/kem/mceliece/internal" + +func fft(out *[exponent][gfBits]uint64, in *[gfBits]uint64) { + radixConversions(in) + butterflies(out, in) +} + +func radixConversions(in *[gfBits]uint64) { + for j := 0; j <= 4; j++ { + for i := 0; i < gfBits; i++ { + for k := 4; k >= j; k-- { + in[i] ^= (in[i] & internal.RadixConversionsMask[k][0]) >> (1 << k) + in[i] ^= (in[i] & internal.RadixConversionsMask[k][1]) >> (1 << k) + } + } + + vecMul(in, in, &internal.RadixConversionsS4096[j]) // scaling + } +} + +func butterflies(out *[exponent][gfBits]uint64, in *[gfBits]uint64) { + tmp := [gfBits]uint64{} + var constsPtr int + // broadcast + for j := 0; j < 64; j++ { + for i := 0; i < gfBits; i++ { + out[j][i] = (in[i] >> internal.ButterfliesReversal4096[j]) & 1 + out[j][i] = -out[j][i] + } + } + + // butterflies + for i := 0; i <= 5; i++ { + s := 1 << i + + for j := 0; j < 64; j += 2 * s { + for k := j; k < j+s; k++ { + vecMul(&tmp, &out[k+s], &internal.ButterfliesConsts4096[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 + } + + // adding the part contributed by x^64 + for i := 0; i < 64; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers4096[i][b] + } + } +} diff --git a/kem/mceliece/mceliece348864/mceliece.go b/kem/mceliece/mceliece348864/mceliece.go new file mode 100644 index 000000000..6f12604e7 --- /dev/null +++ b/kem/mceliece/mceliece348864/mceliece.go @@ -0,0 +1,799 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece348864 implements the IND-CCA2 secure key encapsulation mechanism +// mceliece348864 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 mceliece348864 + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e12" +) + +const ( + sysT = 64 // F(y) is 64 degree + gfBits = gf2e12.Bits + gfMask = gf2e12.Mask + unusedBits = 16 - gfBits + sysN = 3488 + 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 = 261120 + PrivateKeySize = 6492 + CiphertextSize = 96 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +type PublicKey struct { + pk [PublicKeySize]byte +} + +type PrivateKey struct { + sk [PrivateKeySize]byte +} + +type ( + gf = gf2e12.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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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 := gf2e12.Inv(gf2e12.Mul(e, e)) + for j := 0; j < 2*sysT; j++ { + out[j] = gf2e12.Add(out[j], gf2e12.Mul(eInv, c)) + eInv = gf2e12.Mul(eInv, L[i]) + } + } +} + +func min(a, b int) int { + if a > b { + return b + } + return a +} + +// The Berlekamp-Massey algorithm. +// 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 ^= gf2e12.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 = gf2e12.Div(d, b) + for i := 0; i <= sysT; i++ { + C[i] ^= gf2e12.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 := gf2e12.Inv(mat[j][j]) + for c := 0; c <= sysT; c++ { + mat[c][j] = gf2e12.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] ^= gf2e12.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] ^= gf2e12.Mul(a[i], b[j]) + } + } + + for i := (sysT - 1) * 2; i >= sysT; i-- { + // polynomial reduction + + product[i-sysT+3] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= gf2e12.Mul(product[i], 2) + + } + + 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 = gf2e12.Mul(r, a) + r = gf2e12.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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece348864" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece348864/mceliece_test.go b/kem/mceliece/mceliece348864/mceliece_test.go new file mode 100644 index 000000000..7318e0647 --- /dev/null +++ b/kem/mceliece/mceliece348864/mceliece_test.go @@ -0,0 +1,291 @@ +package mceliece348864 + +import ( + "reflect" + "testing" + + "github.com/cloudflare/circl/internal/test" +) + +func fill(t *[sysT]gf, v gf) { + for i := 0; i < sysT; i++ { + t[i] = v + } +} + +func assertEq(t *testing.T, a *[sysT]gf, b []gf) { + if !reflect.DeepEqual(a[:], b) { + test.ReportError(t, b, a[:]) + } +} + +func TestMinimalPolynomial(t *testing.T) { + // tests data generated by Sage + out := [sysT]gf{} + + in := [sysT]gf{ + 1214, 685, 3954, 4010, 38, 1628, 1012, 2473, 3205, 2682, 2677, 3425, 3110, 1093, 2185, 3846, 3695, + 767, 1637, 2096, 505, 1631, 2771, 3982, 1826, 3355, 2038, 1636, 1221, 3228, 1473, 3371, 1443, 2985, + 386, 11, 2376, 529, 828, 2615, 1517, 2414, 3324, 3951, 460, 3457, 974, 2316, 2655, 2889, 2150, 1163, + 1612, 974, 758, 517, 1874, 2819, 1257, 2746, 1559, 1596, 1795, 740, + } + want := [sysT]gf{ + 3991, 3480, 592, 686, 1616, 2086, 804, 3006, 1220, 3868, 2339, 1195, 3235, 3101, 1893, 1285, 280, 3093, + 1919, 1048, 458, 704, 954, 2844, 3679, 3228, 2270, 3886, 717, 1133, 1363, 3026, 3005, 241, 829, 316, 3951, + 2312, 2934, 2610, 1465, 2208, 1915, 2534, 1487, 1266, 3039, 1729, 1585, 3671, 1597, 1189, 3907, 956, 3519, + 3007, 3677, 2253, 1595, 1293, 2029, 2971, 1370, 1240, + } + test.CheckOk(minimalPolynomial(&out, &in), "minimalPolynomial failed", t) + assertEq(t, &want, out[:]) + + in = [sysT]gf{ + 2871, 2450, 516, 137, 3881, 2283, 3696, 3941, 921, 2528, 2099, 3, 3880, 333, 3277, 3787, 141, 2552, 3086, + 1178, 612, 3233, 456, 1222, 3546, 1205, 2786, 877, 2183, 1318, 300, 3583, 1996, 3838, 2263, 3690, 1449, + 3487, 1005, 2206, 525, 779, 1220, 3983, 1697, 3521, 3307, 2752, 1003, 2322, 4022, 1426, 2106, 360, 1261, + 3268, 2050, 3243, 189, 2432, 4048, 362, 2431, 2441, + } + want = [sysT]gf{ + 2143, 2914, 2162, 2520, 1157, 4069, 1048, 237, 3123, 2684, 3638, 3812, 3771, 371, 3156, 2345, 562, 3051, + 3702, 3364, 2452, 352, 2525, 2061, 562, 2696, 868, 108, 295, 910, 1263, 1763, 266, 2752, 1784, 550, 2606, + 703, 32, 387, 2213, 4021, 2388, 2996, 325, 2429, 1533, 3940, 1817, 766, 422, 3198, 289, 3519, 3990, 2593, + 165, 3710, 3932, 3734, 3981, 1382, 2358, 2275, + } + test.CheckOk(minimalPolynomial(&out, &in), "minimalPolynomial failed", t) + assertEq(t, &want, out[:]) +} + +//nolint +func TestPolyMul(t *testing.T) { + res := [sysT]gf{} + arg1 := [sysT]gf{} + arg2 := [sysT]gf{} + + fill(&arg1, 0) + fill(&arg2, 0) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + }) + + fill(&arg1, 0) + fill(&arg2, 1) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, + }) + + fill(&arg1, 1) + fill(&arg2, 0) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, + }) + + fill(&arg1, 0) + fill(&arg2, 5) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, + }) + + fill(&arg1, 5) + fill(&arg2, 0) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, + }) + + fill(&arg1, 0) + fill(&arg2, 1024) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + }) + + fill(&arg1, 1024) + fill(&arg2, 0) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 1, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + }) + + fill(&arg1, 2) + fill(&arg2, 6) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 25, 16, 28, 4, 28, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, + 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, + 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, + }) + + fill(&arg1, 6) + fill(&arg2, 2) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 25, 16, 28, 4, 28, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, + 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, + 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, 16, 4, + }) + + fill(&arg1, 3) + fill(&arg2, 8) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 49, 35, 59, 11, 59, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, + 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, + 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, + 35, 11, + }) + + fill(&arg1, 8) + fill(&arg2, 3) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 49, 35, 59, 11, 59, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, + 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, + 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, 35, 11, + 35, 11, + }) + + fill(&arg1, 125) + fill(&arg2, 19) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 3759, 2455, 3776, 110, 3776, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, + 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, + 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, + 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, + 110, 2455, 110, 2455, 110, + }) + + fill(&arg1, 19) + fill(&arg2, 125) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 3759, 2455, 3776, 110, 3776, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, + 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, + 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, + 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, 110, 2455, + 110, 2455, 110, 2455, 110, + }) + + fill(&arg1, 125) + fill(&arg2, 37) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 3162, 554, 3075, 88, 3075, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, + 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, + 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, + 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, + }) + + fill(&arg1, 37) + fill(&arg2, 125) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 3162, 554, 3075, 88, 3075, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, + 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, + 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, + 88, 554, 88, 554, 88, 554, 88, 554, 88, 554, 88, + }) + + fill(&arg1, 4095) + fill(&arg2, 1) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 4086, 4086, 9, 4094, 9, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + }) + + fill(&arg1, 1) + fill(&arg2, 4095) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 4086, 4086, 9, 4094, 9, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + }) + + fill(&arg1, 8191) + fill(&arg2, 1) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 4068, 4068, 18, 4087, 18, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, + 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, + 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, + 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, + 4068, 4087, 4068, 4087, 4068, 4087, 4068, 4087, + }) + + fill(&arg1, 1) + fill(&arg2, 8191) + arg1[0] = 1 + arg2[0] = 1 + polyMul(&res, &arg1, &arg2) + assertEq(t, &res, []gf{ + 4086, 4086, 9, 4094, 9, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + 4086, 4094, 4086, 4094, 4086, 4094, 4086, 4094, + }) +} diff --git a/kem/mceliece/mceliece348864/pk_gen.go b/kem/mceliece/mceliece348864/pk_gen.go new file mode 100644 index 000000000..88ee6aaa8 --- /dev/null +++ b/kem/mceliece/mceliece348864/pk_gen.go @@ -0,0 +1,259 @@ +// 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 mceliece348864 + +import ( + "github.com/cloudflare/circl/kem/mceliece/internal" +) + +const exponent = 64 + +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 *[gfBits]uint64, in []byte) { + irr := [sysT + 1]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + irr[sysT] = 1 + + for i := 0; i < gfBits; i++ { + out[i] = 0 + } + + for i := sysT; i >= 0; i-- { + for j := 0; j < gfBits; j++ { + out[j] <<= 1 + out[j] |= uint64(irr[i]>>j) & 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 + ) + mat := [pkNRows][nblocksH]uint64{} + var mask uint64 + + irrInt := [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<> 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) + } + + 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 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++ { + + store8(pkp, oneRow[k]) + pkp = pkp[8:] + } + + storeI(pkp, oneRow[k], pkRowBytes%8) + + pkp = pkp[pkRowBytes%8:] + } + + return true +} diff --git a/kem/mceliece/mceliece348864/vec.go b/kem/mceliece/mceliece348864/vec.go new file mode 100644 index 000000000..1771d4067 --- /dev/null +++ b/kem/mceliece/mceliece348864/vec.go @@ -0,0 +1,122 @@ +// 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 mceliece348864 + +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+3] ^= 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{} + + result[0] = in[0] ^ in[6] + result[1] = in[11] + result[2] = in[1] ^ in[7] + result[3] = in[6] + result[4] = in[2] ^ in[11] ^ in[8] + result[5] = in[7] + result[6] = in[3] ^ in[9] + result[7] = in[8] + result[8] = in[4] ^ in[10] + result[9] = in[9] + result[10] = in[5] ^ in[11] + result[11] = in[10] + + 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) + vecMul(out, out, &tmp11) // 1111111111 + + vecSq(out, out) + vecMul(out, out, in) // 11111111111 + + vecSq(out, out) // 111111111110 +} + +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/kem/mceliece/mceliece348864f/benes.go b/kem/mceliece/mceliece348864f/benes.go new file mode 100644 index 000000000..7d96e308f --- /dev/null +++ b/kem/mceliece/mceliece348864f/benes.go @@ -0,0 +1,71 @@ +// Code generated from benes_348864.templ.go. DO NOT EDIT. + +package mceliece348864f + +// Layers of the Beneš network. The required size of `data` and `bits` depends on the value `lgs`. +func layer(data, bits []uint64, lgs int) { + index := 0 + s := 1 << lgs + for i := 0; i < 64; i += s * 2 { + for j := i; j < i+s; j++ { + d := data[j] ^ data[j+s] + d &= bits[index] + index++ + data[j] ^= d + data[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 *[512]byte, bits *[condBytes]byte) { + bs := [64]uint64{} + cond := [64]uint64{} + for i := 0; i < 64; i++ { + bs[i] = load8(r[i*8:]) + } + + transpose64x64(&bs, &bs) + + for low := 0; low <= 5; low++ { + for i := 0; i < 64; i++ { + cond[i] = uint64(load4(bits[low*256+i*4:])) + } + transpose64x64(&cond, &cond) + layer(bs[:], cond[:], low) + } + + transpose64x64(&bs, &bs) + + for low := 0; low <= 5; low++ { + for i := 0; i < 32; i++ { + cond[i] = load8(bits[(low+6)*256+i*8:]) + } + layer(bs[:], cond[:], low) + } + for low := 4; low >= 0; low-- { + for i := 0; i < 32; i++ { + cond[i] = load8(bits[(4-low+6+6)*256+i*8:]) + } + layer(bs[:], cond[:], low) + } + + transpose64x64(&bs, &bs) + + for low := 5; low >= 0; low-- { + for i := 0; i < 64; i++ { + cond[i] = uint64(load4(bits[(5-low+6+6+5)*256+i*4:])) + } + transpose64x64(&cond, &cond) + layer(bs[:], cond[:], low) + } + transpose64x64(&bs, &bs) + + for i := 0; i < 64; i++ { + store8(r[i*8:], bs[i]) + } +} diff --git a/kem/mceliece/mceliece348864f/fft.go b/kem/mceliece/mceliece348864f/fft.go new file mode 100644 index 000000000..97668204b --- /dev/null +++ b/kem/mceliece/mceliece348864f/fft.go @@ -0,0 +1,65 @@ +// Code generated from fft_348864.templ.go. DO NOT EDIT. + +// The following code is translated from the C `vec` Additional Implementation +// from the NIST round 4 submission package. + +package mceliece348864f + +import "github.com/cloudflare/circl/kem/mceliece/internal" + +func fft(out *[exponent][gfBits]uint64, in *[gfBits]uint64) { + radixConversions(in) + butterflies(out, in) +} + +func radixConversions(in *[gfBits]uint64) { + for j := 0; j <= 4; j++ { + for i := 0; i < gfBits; i++ { + for k := 4; k >= j; k-- { + in[i] ^= (in[i] & internal.RadixConversionsMask[k][0]) >> (1 << k) + in[i] ^= (in[i] & internal.RadixConversionsMask[k][1]) >> (1 << k) + } + } + + vecMul(in, in, &internal.RadixConversionsS4096[j]) // scaling + } +} + +func butterflies(out *[exponent][gfBits]uint64, in *[gfBits]uint64) { + tmp := [gfBits]uint64{} + var constsPtr int + // broadcast + for j := 0; j < 64; j++ { + for i := 0; i < gfBits; i++ { + out[j][i] = (in[i] >> internal.ButterfliesReversal4096[j]) & 1 + out[j][i] = -out[j][i] + } + } + + // butterflies + for i := 0; i <= 5; i++ { + s := 1 << i + + for j := 0; j < 64; j += 2 * s { + for k := j; k < j+s; k++ { + vecMul(&tmp, &out[k+s], &internal.ButterfliesConsts4096[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 + } + + // adding the part contributed by x^64 + for i := 0; i < 64; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers4096[i][b] + } + } +} diff --git a/kem/mceliece/mceliece348864f/mceliece.go b/kem/mceliece/mceliece348864f/mceliece.go new file mode 100644 index 000000000..6e444bf4f --- /dev/null +++ b/kem/mceliece/mceliece348864f/mceliece.go @@ -0,0 +1,799 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece348864f implements the IND-CCA2 secure key encapsulation mechanism +// mceliece348864f 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 mceliece348864f + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e12" +) + +const ( + sysT = 64 // F(y) is 64 degree + gfBits = gf2e12.Bits + gfMask = gf2e12.Mask + unusedBits = 16 - gfBits + sysN = 3488 + 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 = 261120 + PrivateKeySize = 6492 + CiphertextSize = 96 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +type PublicKey struct { + pk [PublicKeySize]byte +} + +type PrivateKey struct { + sk [PrivateKeySize]byte +} + +type ( + gf = gf2e12.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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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 := gf2e12.Inv(gf2e12.Mul(e, e)) + for j := 0; j < 2*sysT; j++ { + out[j] = gf2e12.Add(out[j], gf2e12.Mul(eInv, c)) + eInv = gf2e12.Mul(eInv, L[i]) + } + } +} + +func min(a, b int) int { + if a > b { + return b + } + return a +} + +// The Berlekamp-Massey algorithm. +// 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 ^= gf2e12.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 = gf2e12.Div(d, b) + for i := 0; i <= sysT; i++ { + C[i] ^= gf2e12.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 := gf2e12.Inv(mat[j][j]) + for c := 0; c <= sysT; c++ { + mat[c][j] = gf2e12.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] ^= gf2e12.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] ^= gf2e12.Mul(a[i], b[j]) + } + } + + for i := (sysT - 1) * 2; i >= sysT; i-- { + // polynomial reduction + + product[i-sysT+3] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= gf2e12.Mul(product[i], 2) + + } + + 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 = gf2e12.Mul(r, a) + r = gf2e12.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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece348864f" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece348864f/pk_gen.go b/kem/mceliece/mceliece348864f/pk_gen.go new file mode 100644 index 000000000..238ab382a --- /dev/null +++ b/kem/mceliece/mceliece348864f/pk_gen.go @@ -0,0 +1,306 @@ +// 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 mceliece348864f + +import ( + "github.com/cloudflare/circl/kem/mceliece/internal" +) + +const exponent = 64 + +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 *[gfBits]uint64, in []byte) { + irr := [sysT + 1]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + irr[sysT] = 1 + + for i := 0; i < gfBits; i++ { + out[i] = 0 + } + + for i := sysT; i >= 0; i-- { + for j := 0; j < gfBits; j++ { + out[j] <<= 1 + out[j] |= uint64(irr[i]>>j) & 1 + } + } +} + +// Return number of trailing zeros of the non-zero input `input` +func ctz(in uint64) int { + m := 0 + r := 0 + for i := 0; i < 64; i++ { + b := int((in >> i) & 1) + m |= b + r += (m ^ 1) & (b ^ 1) + } + return r +} + +// Takes two 16-bit integers and determines whether they are equal (all bits set) or different (0) +func sameMask64(x, y uint16) uint64 { + mask := uint64(x ^ y) + mask -= 1 + mask >>= 63 + mask = -mask + return mask +} + +// Move columns in matrix `mat` +func movColumns(mat *[pkNRows][(sysN + 63) / 64]uint64, pi []int16, pivots *uint64) bool { + buf := [64]uint64{} + ctzList := [32]uint64{} + row := pkNRows - 32 + blockIdx := row / 64 + + // extract the 32x64 matrix + + for i := 0; i < 32; i++ { + buf[i] = (mat[row+i][blockIdx+0] >> 32) | (mat[row+i][blockIdx+1] << 32) + } + + // compute the column indices of pivots by Gaussian elimination. + // the indices are stored in ctz_list + + *pivots = 0 + + for i := 0; i < 32; i++ { + t := buf[i] + for j := i + 1; j < 32; j++ { + t |= buf[j] + } + if t == 0 { + return false // return if buf is not full rank + } + s := ctz(t) + ctzList[i] = uint64(s) + *pivots |= 1 << s + + for j := i + 1; j < 32; j++ { + mask := (buf[i] >> s) & 1 + mask -= 1 + buf[i] ^= buf[j] & mask + } + for j := i + 1; j < 32; j++ { + mask := (buf[j] >> s) & 1 + mask = -mask + buf[j] ^= buf[i] & mask + } + } + + // updating permutation + for j := 0; j < 32; j++ { + for k := j + 1; k < 64; k++ { + d := uint64(pi[row+j] ^ pi[row+k]) + d &= sameMask64(uint16(k), uint16(ctzList[j])) & 0xFFFF + pi[row+j] ^= int16(d) + pi[row+k] ^= int16(d) + } + } + + // moving columns of mat according to the column indices of pivots + for i := 0; i < pkNRows; i++ { + + t := (mat[i][blockIdx+0] >> 32) | (mat[i][blockIdx+1] << 32) + + for j := 0; j < 32; j++ { + d := t >> j + d ^= t >> ctzList[j] + d &= 1 + + t ^= d << ctzList[j] + t ^= d << j + } + + mat[i][blockIdx+0] = (mat[i][blockIdx+0] << 32 >> 32) | (t << 32) + mat[i][blockIdx+1] = (mat[i][blockIdx+1] >> 32 << 32) | (t >> 32) + + } + + return true +} + +// 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 + ) + mat := [pkNRows][nblocksH]uint64{} + var mask uint64 + + irrInt := [gfBits]uint64{} + + consts := [exponent][gfBits]uint64{} + eval := [exponent][gfBits]uint64{} + prod := [exponent][gfBits]uint64{} + tmp := [gfBits]uint64{} + list := [1 << gfBits]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<> 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 < nblocksH; j++ { + for k := 0; k < gfBits; k++ { + mat[k][j] = prod[j][k] + } + } + + for i := 1; i < sysT; i++ { + for j := 0; j < nblocksH; j++ { + vecMul(&prod[j], &prod[j], &consts[j]) + for k := 0; k < gfBits; k++ { + mat[i*gfBits+k][j] = prod[j][k] + } + } + } + + // gaussian elimination + + for row := 0; row < pkNRows; row++ { + i := row >> 6 + j := row & 63 + + if row == pkNRows-32 { + if !movColumns(&mat, pi[:], pivots) { + return false + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[row][i] >> j + mask &= 1 + mask -= 1 + + for c := 0; c < nblocksH; c++ { + mat[row][c] ^= mat[k][c] & mask + } + + } + // return if not systematic + if ((mat[row][i] >> j) & 1) == 0 { + return false + } + + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + } + + pkp := pk[:] + + for i := 0; i < pkNRows; i++ { + + var j int + for j = nblocksI; j < nblocksH-1; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + storeI(pkp, mat[i][j], pkRowBytes%8) + pkp = pkp[pkRowBytes%8:] + + } + + return true +} diff --git a/kem/mceliece/mceliece348864f/pk_gen_test.go b/kem/mceliece/mceliece348864f/pk_gen_test.go new file mode 100644 index 000000000..a59c9a3d4 --- /dev/null +++ b/kem/mceliece/mceliece348864f/pk_gen_test.go @@ -0,0 +1,44 @@ +package mceliece348864f + +import ( + "testing" + + "github.com/cloudflare/circl/internal/test" +) + +func TestCtz(t *testing.T) { + expected := []int{ + 64, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, + 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, + 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, + 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, + 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, + 1, 0, 4, 0, 1, 0, + } + for i := uint64(0); i < 100; i++ { + got := ctz(i) + if got != expected[i] { + test.ReportError(t, got, expected[i]) + } + } +} + +func TestSameMask(t *testing.T) { + expected := []uint64{ + 0xFFFFFFFFFFFFFFFF, 0, 0, 0, 0, 0, + 0xFFFFFFFFFFFFFFFF, 0, 0, 0, 0, 0, + 0xFFFFFFFFFFFFFFFF, 0, 0, 0, 0, 0, + 0xFFFFFFFFFFFFFFFF, 0, 0, 0, 0, 0, + 0xFFFFFFFFFFFFFFFF, + } + for i := 0; i < 5; i++ { + for j := 0; j < 5; j++ { + got := sameMask64(uint16(i), uint16(j)) + want := expected[i*5+j] + if got != want { + test.ReportError(t, got, want) + } + } + } +} diff --git a/kem/mceliece/mceliece348864f/vec.go b/kem/mceliece/mceliece348864f/vec.go new file mode 100644 index 000000000..209ffe029 --- /dev/null +++ b/kem/mceliece/mceliece348864f/vec.go @@ -0,0 +1,122 @@ +// 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 mceliece348864f + +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+3] ^= 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{} + + result[0] = in[0] ^ in[6] + result[1] = in[11] + result[2] = in[1] ^ in[7] + result[3] = in[6] + result[4] = in[2] ^ in[11] ^ in[8] + result[5] = in[7] + result[6] = in[3] ^ in[9] + result[7] = in[8] + result[8] = in[4] ^ in[10] + result[9] = in[9] + result[10] = in[5] ^ in[11] + result[11] = in[10] + + 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) + vecMul(out, out, &tmp11) // 1111111111 + + vecSq(out, out) + vecMul(out, out, in) // 11111111111 + + vecSq(out, out) // 111111111110 +} + +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/kem/mceliece/mceliece460896/benes.go b/kem/mceliece/mceliece460896/benes.go new file mode 100644 index 000000000..323e9567c --- /dev/null +++ b/kem/mceliece/mceliece460896/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece460896 + +// 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/kem/mceliece/mceliece460896/benes_test.go b/kem/mceliece/mceliece460896/benes_test.go new file mode 100644 index 000000000..d2c129272 --- /dev/null +++ b/kem/mceliece/mceliece460896/benes_test.go @@ -0,0 +1,99 @@ +package mceliece460896 + +import ( + "fmt" + "reflect" + "testing" + + "github.com/cloudflare/circl/internal/test" + "github.com/cloudflare/circl/kem/mceliece/testdata" +) + +const testPath = "../testdata/testdata.txt.bz2" + +func TestLayerIn(t *testing.T) { + data0, err := testdata.FindTestDataU64("mceliece460896_benes_layer_in_data0_before", testPath) + if err != nil { + t.Fatal(err) + } + data1, err := testdata.FindTestDataU64("mceliece460896_benes_layer_in_data1_before", testPath) + if err != nil { + t.Fatal(err) + } + data := [2][64]uint64{} + copy(data[0][:], data0) + copy(data[1][:], data1) + bitsArg, err := testdata.FindTestDataU64("mceliece460896_benes_layer_in_bits", testPath) + if err != nil { + t.Fatal(err) + } + layerIn(&data, (*[64]uint64)(bitsArg), 0) + want0, err := testdata.FindTestDataU64("mceliece460896_benes_layer_in_data0_after", testPath) + if err != nil { + t.Fatal(err) + } + want1, err := testdata.FindTestDataU64("mceliece460896_benes_layer_in_data1_after", testPath) + if err != nil { + t.Fatal(err) + } + want := [2][64]uint64{} + copy(want[0][:], want0) + copy(want[1][:], want1) + if !reflect.DeepEqual(want, data) { + test.ReportError(t, data, want) + } +} + +func TestLayerEx(t *testing.T) { + data := [2][64]uint64{} + bits := [64]uint64{} + for i := uint64(0); i < 64; i++ { + data[0][i] = 0xFC81 ^ (i * 17) + data[1][i] = 0x9837 ^ (i * 3) + bits[i] = i << 3 + } + layerEx(&data, &bits, 5) + + want := [2][64]uint64{ + { + 0xFC81, 0xFC90, 0xFCA3, 0xFCB2, 0xFCE5, 0xFCF4, 0xFCC7, 0xFCD6, 0xFC09, 0xFC18, + 0xFC6B, 0xFC7A, 0xFC6D, 0xFC7C, 0xFC0F, 0xFC1E, 0xFD91, 0xFDA0, 0xFDB3, 0xFDC2, + 0xFDF5, 0xFD44, 0xFD57, 0xFD26, 0xFD19, 0xFD68, 0xFD7B, 0xFD4A, 0xFD7D, 0xFD8C, + 0xFD9F, 0xFEAE, 0xFEA1, 0xFEB0, 0xFEC3, 0xFED2, 0xFEC5, 0xFED4, 0xFE27, 0xFE36, + 0xFE29, 0xFE38, 0xFE0B, 0xFE1A, 0xFE4D, 0xFE5C, 0xFFEF, 0xFFFE, 0xFFB1, 0xFFC0, + 0xFFD3, 0xFFE2, 0xFFD5, 0xFFA4, 0xFFB7, 0xFF06, 0xFF39, 0xFF08, 0xFF1B, 0xFF6A, + 0xFF5D, 0xF86C, 0xF87F, 0xF88E, + }, { + 0x9837, 0x9834, 0x9831, 0x983E, 0x981B, 0x9818, 0x9805, 0x9802, 0x986F, 0x986C, + 0x9869, 0x9816, 0x9833, 0x9830, 0x983D, 0x983A, 0x9887, 0x9884, 0x9881, 0x988E, + 0x98AB, 0x98A8, 0x98D5, 0x98D2, 0x98BF, 0x98BC, 0x98B9, 0x98A6, 0x9883, 0x9880, + 0x988D, 0x988A, 0x9857, 0x9854, 0x9851, 0x985E, 0x987B, 0x9878, 0x9865, 0x9862, + 0x980F, 0x980C, 0x9809, 0x98B6, 0x9893, 0x9890, 0x989D, 0x989A, 0x9827, 0x9824, + 0x9821, 0x982E, 0x980B, 0x9808, 0x9835, 0x9832, 0x985F, 0x985C, 0x9859, 0x9846, + 0x9863, 0x9860, 0x986D, 0x986A, + }, + } + + if !reflect.DeepEqual(want, data) { + test.ReportError(t, data, want) + } +} + +func TestBenes(t *testing.T) { + rArg, err := testdata.FindTestDataByte("mceliece460896orlarger_benes_apply_benes_r_before", testPath) + if err != nil { + t.Fatal(err) + } + bitsArg, err := testdata.FindTestDataByte("mceliece460896orlarger_benes_apply_benes_bits", testPath) + if err != nil { + t.Fatal(err) + } + applyBenes((*[1024]byte)(rArg), (*[condBytes]byte)(bitsArg)) + want, err := testdata.FindTestDataByte("mceliece460896orlarger_benes_apply_benes_r_after", testPath) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(want, rArg) { + test.ReportError(t, fmt.Sprintf("%X", rArg), fmt.Sprintf("%X", want)) + } +} diff --git a/kem/mceliece/mceliece460896/fft.go b/kem/mceliece/mceliece460896/fft.go new file mode 100644 index 000000000..84a82578c --- /dev/null +++ b/kem/mceliece/mceliece460896/fft.go @@ -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 mceliece460896 + +import "github.com/cloudflare/circl/kem/mceliece/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/kem/mceliece/mceliece460896/mceliece.go b/kem/mceliece/mceliece460896/mceliece.go new file mode 100644 index 000000000..45b3e52b5 --- /dev/null +++ b/kem/mceliece/mceliece460896/mceliece.go @@ -0,0 +1,800 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece460896 implements the IND-CCA2 secure key encapsulation mechanism +// mceliece460896 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 mceliece460896 + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e13" +) + +const ( + sysT = 96 // F(y) is 64 degree + gfBits = gf2e13.Bits + gfMask = gf2e13.Mask + unusedBits = 16 - gfBits + sysN = 4608 + 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 = 524160 + PrivateKeySize = 13608 + CiphertextSize = 156 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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. +// 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+10] ^= product[i] + product[i-sysT+9] ^= product[i] + product[i-sysT+6] ^= product[i] + product[i-sysT] ^= 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece460896" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece460896/pk_gen.go b/kem/mceliece/mceliece460896/pk_gen.go new file mode 100644 index 000000000..5edab06e2 --- /dev/null +++ b/kem/mceliece/mceliece460896/pk_gen.go @@ -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 mceliece460896 + +import ( + "github.com/cloudflare/circl/kem/mceliece/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<> 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 = pkp[pkRowBytes%8:] + } + + return true +} diff --git a/kem/mceliece/mceliece460896/vec.go b/kem/mceliece/mceliece460896/vec.go new file mode 100644 index 000000000..d9153ddc3 --- /dev/null +++ b/kem/mceliece/mceliece460896/vec.go @@ -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 mceliece460896 + +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/kem/mceliece/mceliece460896f/benes.go b/kem/mceliece/mceliece460896f/benes.go new file mode 100644 index 000000000..cc855b4ae --- /dev/null +++ b/kem/mceliece/mceliece460896f/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece460896f + +// 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/kem/mceliece/mceliece460896f/fft.go b/kem/mceliece/mceliece460896f/fft.go new file mode 100644 index 000000000..8550814b0 --- /dev/null +++ b/kem/mceliece/mceliece460896f/fft.go @@ -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 mceliece460896f + +import "github.com/cloudflare/circl/kem/mceliece/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/kem/mceliece/mceliece460896f/mceliece.go b/kem/mceliece/mceliece460896f/mceliece.go new file mode 100644 index 000000000..dcb585909 --- /dev/null +++ b/kem/mceliece/mceliece460896f/mceliece.go @@ -0,0 +1,800 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece460896f implements the IND-CCA2 secure key encapsulation mechanism +// mceliece460896f 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 mceliece460896f + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e13" +) + +const ( + sysT = 96 // F(y) is 64 degree + gfBits = gf2e13.Bits + gfMask = gf2e13.Mask + unusedBits = 16 - gfBits + sysN = 4608 + 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 = 524160 + PrivateKeySize = 13608 + CiphertextSize = 156 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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. +// 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+10] ^= product[i] + product[i-sysT+9] ^= product[i] + product[i-sysT+6] ^= product[i] + product[i-sysT] ^= 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece460896f" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece460896f/pk_gen.go b/kem/mceliece/mceliece460896f/pk_gen.go new file mode 100644 index 000000000..3e048ac79 --- /dev/null +++ b/kem/mceliece/mceliece460896f/pk_gen.go @@ -0,0 +1,312 @@ +// 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 mceliece460896f + +import ( + "github.com/cloudflare/circl/kem/mceliece/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] + } +} + +// Return number of trailing zeros of the non-zero input `input` +func ctz(in uint64) int { + m := 0 + r := 0 + for i := 0; i < 64; i++ { + b := int((in >> i) & 1) + m |= b + r += (m ^ 1) & (b ^ 1) + } + return r +} + +// Takes two 16-bit integers and determines whether they are equal (all bits set) or different (0) +func sameMask64(x, y uint16) uint64 { + mask := uint64(x ^ y) + mask -= 1 + mask >>= 63 + mask = -mask + return mask +} + +// Move columns in matrix `mat` +func movColumns(mat *[pkNRows][(sysN + 63) / 64]uint64, pi []int16, pivots *uint64) bool { + buf := [64]uint64{} + ctzList := [32]uint64{} + row := pkNRows - 32 + blockIdx := row / 64 + + // extract the 32x64 matrix + + for i := 0; i < 32; i++ { + buf[i] = mat[row+i][blockIdx] + } + + // compute the column indices of pivots by Gaussian elimination. + // the indices are stored in ctz_list + + *pivots = 0 + + for i := 0; i < 32; i++ { + t := buf[i] + for j := i + 1; j < 32; j++ { + t |= buf[j] + } + if t == 0 { + return false // return if buf is not full rank + } + s := ctz(t) + ctzList[i] = uint64(s) + *pivots |= 1 << s + + for j := i + 1; j < 32; j++ { + mask := (buf[i] >> s) & 1 + mask -= 1 + buf[i] ^= buf[j] & mask + } + for j := i + 1; j < 32; j++ { + mask := (buf[j] >> s) & 1 + mask = -mask + buf[j] ^= buf[i] & mask + } + } + + // updating permutation + for j := 0; j < 32; j++ { + for k := j + 1; k < 64; k++ { + d := uint64(pi[row+j] ^ pi[row+k]) + d &= sameMask64(uint16(k), uint16(ctzList[j])) + pi[row+j] ^= int16(d) + pi[row+k] ^= int16(d) + } + } + + // moving columns of mat according to the column indices of pivots + for i := 0; i < pkNRows; i++ { + + t := mat[i][blockIdx] + + for j := 0; j < 32; j++ { + d := t >> j + d ^= t >> ctzList[j] + d &= 1 + + t ^= d << ctzList[j] + t ^= d << j + } + + mat[i][blockIdx] = t + + } + + return true +} + +// 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{} + + // 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<> 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 < nblocksH; j++ { + for k := 0; k < gfBits; k++ { + mat[k][j] = prod[j][k] + } + } + + for i := 1; i < sysT; i++ { + for j := 0; j < nblocksH; j++ { + vecMul(&prod[j], &prod[j], &consts[j]) + for k := 0; k < gfBits; k++ { + mat[i*gfBits+k][j] = prod[j][k] + } + } + } + + // gaussian elimination + + for row := 0; row < pkNRows; row++ { + i := row >> 6 + j := row & 63 + + if row == pkNRows-32 { + if !movColumns(&mat, pi[:], pivots) { + return false + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[row][i] >> j + mask &= 1 + mask -= 1 + + for c := 0; c < nblocksH; c++ { + mat[row][c] ^= mat[k][c] & mask + } + + } + // return if not systematic + if ((mat[row][i] >> j) & 1) == 0 { + return false + } + + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + } + + pkp := pk[:] + + for i := 0; i < pkNRows; i++ { + + storeI(pkp, mat[i][nblocksI-1]>>tail, (64-tail)/8) + pkp = pkp[(64-tail)/8:] + for j := nblocksI; j < nblocksH; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + + } + + return true +} diff --git a/kem/mceliece/mceliece460896f/vec.go b/kem/mceliece/mceliece460896f/vec.go new file mode 100644 index 000000000..3c7d265a6 --- /dev/null +++ b/kem/mceliece/mceliece460896f/vec.go @@ -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 mceliece460896f + +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/kem/mceliece/mceliece6688128/benes.go b/kem/mceliece/mceliece6688128/benes.go new file mode 100644 index 000000000..b6b6e8e6c --- /dev/null +++ b/kem/mceliece/mceliece6688128/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece6688128 + +// 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/kem/mceliece/mceliece6688128/fft.go b/kem/mceliece/mceliece6688128/fft.go new file mode 100644 index 000000000..3d76cf852 --- /dev/null +++ b/kem/mceliece/mceliece6688128/fft.go @@ -0,0 +1,215 @@ +// 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 mceliece6688128 + +import "github.com/cloudflare/circl/kem/mceliece/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 + } + + // adding the part contributed by x^128 + for i := 0; i < 128; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers8192[i][b] + } + } +} diff --git a/kem/mceliece/mceliece6688128/mceliece.go b/kem/mceliece/mceliece6688128/mceliece.go new file mode 100644 index 000000000..af8b7f1b5 --- /dev/null +++ b/kem/mceliece/mceliece6688128/mceliece.go @@ -0,0 +1,800 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece6688128 implements the IND-CCA2 secure key encapsulation mechanism +// mceliece6688128 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 mceliece6688128 + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e13" +) + +const ( + sysT = 128 // F(y) is 64 degree + gfBits = gf2e13.Bits + gfMask = gf2e13.Mask + unusedBits = 16 - gfBits + sysN = 6688 + 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 = 1044992 + PrivateKeySize = 13932 + CiphertextSize = 208 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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. +// 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+7] ^= product[i] + product[i-sysT+2] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece6688128" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece6688128/pk_gen.go b/kem/mceliece/mceliece6688128/pk_gen.go new file mode 100644 index 000000000..4e06f4046 --- /dev/null +++ b/kem/mceliece/mceliece6688128/pk_gen.go @@ -0,0 +1,262 @@ +// 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 mceliece6688128 + +import ( + "github.com/cloudflare/circl/kem/mceliece/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) { + var ( + v0 uint64 + v1 uint64 + ) + irr := [sysT]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + for i := 0; i < gfBits; i++ { + for j := 63; j >= 0; j-- { + v0 <<= 1 + v1 <<= 1 + v0 |= uint64(irr[j]>>i) & 1 + v1 |= uint64(irr[j+64]>>i) & 1 + } + + out[0][i] = v0 + out[1][i] = v1 + } +} + +// 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 + ) + 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<> 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) + } + + 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 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++ { + + store8(pkp, oneRow[k]) + pkp = pkp[8:] + } + + storeI(pkp, oneRow[k], pkRowBytes%8) + + pkp = pkp[pkRowBytes%8:] + } + + return true +} diff --git a/kem/mceliece/mceliece6688128/vec.go b/kem/mceliece/mceliece6688128/vec.go new file mode 100644 index 000000000..743373406 --- /dev/null +++ b/kem/mceliece/mceliece6688128/vec.go @@ -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 mceliece6688128 + +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/kem/mceliece/mceliece6688128f/benes.go b/kem/mceliece/mceliece6688128f/benes.go new file mode 100644 index 000000000..8d2c76ef6 --- /dev/null +++ b/kem/mceliece/mceliece6688128f/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece6688128f + +// 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/kem/mceliece/mceliece6688128f/fft.go b/kem/mceliece/mceliece6688128f/fft.go new file mode 100644 index 000000000..9f72ee1ac --- /dev/null +++ b/kem/mceliece/mceliece6688128f/fft.go @@ -0,0 +1,215 @@ +// 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 mceliece6688128f + +import "github.com/cloudflare/circl/kem/mceliece/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 + } + + // adding the part contributed by x^128 + for i := 0; i < 128; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers8192[i][b] + } + } +} diff --git a/kem/mceliece/mceliece6688128f/mceliece.go b/kem/mceliece/mceliece6688128f/mceliece.go new file mode 100644 index 000000000..a03e0fc9f --- /dev/null +++ b/kem/mceliece/mceliece6688128f/mceliece.go @@ -0,0 +1,800 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece6688128f implements the IND-CCA2 secure key encapsulation mechanism +// mceliece6688128f 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 mceliece6688128f + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e13" +) + +const ( + sysT = 128 // F(y) is 64 degree + gfBits = gf2e13.Bits + gfMask = gf2e13.Mask + unusedBits = 16 - gfBits + sysN = 6688 + 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 = 1044992 + PrivateKeySize = 13932 + CiphertextSize = 208 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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. +// 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+7] ^= product[i] + product[i-sysT+2] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece6688128f" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece6688128f/pk_gen.go b/kem/mceliece/mceliece6688128f/pk_gen.go new file mode 100644 index 000000000..f1a0aae8b --- /dev/null +++ b/kem/mceliece/mceliece6688128f/pk_gen.go @@ -0,0 +1,309 @@ +// 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 mceliece6688128f + +import ( + "github.com/cloudflare/circl/kem/mceliece/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) { + var ( + v0 uint64 + v1 uint64 + ) + irr := [sysT]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + for i := 0; i < gfBits; i++ { + for j := 63; j >= 0; j-- { + v0 <<= 1 + v1 <<= 1 + v0 |= uint64(irr[j]>>i) & 1 + v1 |= uint64(irr[j+64]>>i) & 1 + } + + out[0][i] = v0 + out[1][i] = v1 + } +} + +// Return number of trailing zeros of the non-zero input `input` +func ctz(in uint64) int { + m := 0 + r := 0 + for i := 0; i < 64; i++ { + b := int((in >> i) & 1) + m |= b + r += (m ^ 1) & (b ^ 1) + } + return r +} + +// Takes two 16-bit integers and determines whether they are equal (all bits set) or different (0) +func sameMask64(x, y uint16) uint64 { + mask := uint64(x ^ y) + mask -= 1 + mask >>= 63 + mask = -mask + return mask +} + +// Move columns in matrix `mat` +func movColumns(mat *[pkNRows][(sysN + 63) / 64]uint64, pi []int16, pivots *uint64) bool { + buf := [64]uint64{} + ctzList := [32]uint64{} + row := pkNRows - 32 + blockIdx := row / 64 + + // extract the 32x64 matrix + + for i := 0; i < 32; i++ { + buf[i] = (mat[row+i][blockIdx+0] >> 32) | (mat[row+i][blockIdx+1] << 32) + } + + // compute the column indices of pivots by Gaussian elimination. + // the indices are stored in ctz_list + + *pivots = 0 + + for i := 0; i < 32; i++ { + t := buf[i] + for j := i + 1; j < 32; j++ { + t |= buf[j] + } + if t == 0 { + return false // return if buf is not full rank + } + s := ctz(t) + ctzList[i] = uint64(s) + *pivots |= 1 << s + + for j := i + 1; j < 32; j++ { + mask := (buf[i] >> s) & 1 + mask -= 1 + buf[i] ^= buf[j] & mask + } + for j := i + 1; j < 32; j++ { + mask := (buf[j] >> s) & 1 + mask = -mask + buf[j] ^= buf[i] & mask + } + } + + // updating permutation + for j := 0; j < 32; j++ { + for k := j + 1; k < 64; k++ { + d := uint64(pi[row+j] ^ pi[row+k]) + d &= sameMask64(uint16(k), uint16(ctzList[j])) + pi[row+j] ^= int16(d) + pi[row+k] ^= int16(d) + } + } + + // moving columns of mat according to the column indices of pivots + for i := 0; i < pkNRows; i++ { + + t := (mat[i][blockIdx+0] >> 32) | (mat[i][blockIdx+1] << 32) + + for j := 0; j < 32; j++ { + d := t >> j + d ^= t >> ctzList[j] + d &= 1 + + t ^= d << ctzList[j] + t ^= d << j + } + + mat[i][blockIdx+0] = (mat[i][blockIdx+0] << 32 >> 32) | (t << 32) + mat[i][blockIdx+1] = (mat[i][blockIdx+1] >> 32 << 32) | (t >> 32) + + } + + return true +} + +// 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 + ) + 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{} + + // 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<> 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 < nblocksH; j++ { + for k := 0; k < gfBits; k++ { + mat[k][j] = prod[j][k] + } + } + + for i := 1; i < sysT; i++ { + for j := 0; j < nblocksH; j++ { + vecMul(&prod[j], &prod[j], &consts[j]) + for k := 0; k < gfBits; k++ { + mat[i*gfBits+k][j] = prod[j][k] + } + } + } + + // gaussian elimination + + for row := 0; row < pkNRows; row++ { + i := row >> 6 + j := row & 63 + + if row == pkNRows-32 { + if !movColumns(&mat, pi[:], pivots) { + return false + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[row][i] >> j + mask &= 1 + mask -= 1 + + for c := 0; c < nblocksH; c++ { + mat[row][c] ^= mat[k][c] & mask + } + + } + // return if not systematic + if ((mat[row][i] >> j) & 1) == 0 { + return false + } + + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + } + + pkp := pk[:] + + for i := 0; i < pkNRows; i++ { + + var j int + for j = nblocksI; j < nblocksH-1; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + storeI(pkp, mat[i][j], pkRowBytes%8) + pkp = pkp[pkRowBytes%8:] + + } + + return true +} diff --git a/kem/mceliece/mceliece6688128f/vec.go b/kem/mceliece/mceliece6688128f/vec.go new file mode 100644 index 000000000..ff5381343 --- /dev/null +++ b/kem/mceliece/mceliece6688128f/vec.go @@ -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 mceliece6688128f + +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/kem/mceliece/mceliece6960119/benes.go b/kem/mceliece/mceliece6960119/benes.go new file mode 100644 index 000000000..23b908668 --- /dev/null +++ b/kem/mceliece/mceliece6960119/benes.go @@ -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/kem/mceliece/mceliece6960119/fft.go b/kem/mceliece/mceliece6960119/fft.go new file mode 100644 index 000000000..97b046ec9 --- /dev/null +++ b/kem/mceliece/mceliece6960119/fft.go @@ -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 "github.com/cloudflare/circl/kem/mceliece/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/kem/mceliece/mceliece6960119/mceliece.go b/kem/mceliece/mceliece6960119/mceliece.go new file mode 100644 index 000000000..8d5cfcfcd --- /dev/null +++ b/kem/mceliece/mceliece6960119/mceliece.go @@ -0,0 +1,788 @@ +// 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 ( + "bytes" + cryptoRand "crypto/rand" + "fmt" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/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 +) + +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<>= 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. +// 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece6960119" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece6960119/operations.go b/kem/mceliece/mceliece6960119/operations.go new file mode 100644 index 000000000..77dbd4e8f --- /dev/null +++ b/kem/mceliece/mceliece6960119/operations.go @@ -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/kem/mceliece/mceliece6960119/pk_gen.go b/kem/mceliece/mceliece6960119/pk_gen.go new file mode 100644 index 000000000..5f0e1e09e --- /dev/null +++ b/kem/mceliece/mceliece6960119/pk_gen.go @@ -0,0 +1,282 @@ +// 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 ( + "github.com/cloudflare/circl/kem/mceliece/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<> 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/kem/mceliece/mceliece6960119/vec.go b/kem/mceliece/mceliece6960119/vec.go new file mode 100644 index 000000000..da79d4457 --- /dev/null +++ b/kem/mceliece/mceliece6960119/vec.go @@ -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/kem/mceliece/mceliece6960119f/benes.go b/kem/mceliece/mceliece6960119f/benes.go new file mode 100644 index 000000000..b6c191311 --- /dev/null +++ b/kem/mceliece/mceliece6960119f/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece6960119f + +// 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/kem/mceliece/mceliece6960119f/fft.go b/kem/mceliece/mceliece6960119f/fft.go new file mode 100644 index 000000000..677b99bf7 --- /dev/null +++ b/kem/mceliece/mceliece6960119f/fft.go @@ -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 mceliece6960119f + +import "github.com/cloudflare/circl/kem/mceliece/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/kem/mceliece/mceliece6960119f/mceliece.go b/kem/mceliece/mceliece6960119f/mceliece.go new file mode 100644 index 000000000..666b723d4 --- /dev/null +++ b/kem/mceliece/mceliece6960119f/mceliece.go @@ -0,0 +1,788 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece6960119f implements the IND-CCA2 secure key encapsulation mechanism +// mceliece6960119f 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 mceliece6960119f + +import ( + "bytes" + cryptoRand "crypto/rand" + "fmt" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/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 +) + +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<>= 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. +// 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece6960119f" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece6960119f/operations.go b/kem/mceliece/mceliece6960119f/operations.go new file mode 100644 index 000000000..42b4d0df1 --- /dev/null +++ b/kem/mceliece/mceliece6960119f/operations.go @@ -0,0 +1,57 @@ +// Code generated from operations_6960119.templ.go. DO NOT EDIT. + +package mceliece6960119f + +// 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/kem/mceliece/mceliece6960119f/pk_gen.go b/kem/mceliece/mceliece6960119f/pk_gen.go new file mode 100644 index 000000000..737739b46 --- /dev/null +++ b/kem/mceliece/mceliece6960119f/pk_gen.go @@ -0,0 +1,319 @@ +// 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 mceliece6960119f + +import ( + "github.com/cloudflare/circl/kem/mceliece/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] + } +} + +// Return number of trailing zeros of the non-zero input `input` +func ctz(in uint64) int { + m := 0 + r := 0 + for i := 0; i < 64; i++ { + b := int((in >> i) & 1) + m |= b + r += (m ^ 1) & (b ^ 1) + } + return r +} + +// Takes two 16-bit integers and determines whether they are equal (all bits set) or different (0) +func sameMask64(x, y uint16) uint64 { + mask := uint64(x ^ y) + mask -= 1 + mask >>= 63 + mask = -mask + return mask +} + +// Move columns in matrix `mat` +func movColumns(mat *[pkNRows][(sysN + 63) / 64]uint64, pi []int16, pivots *uint64) bool { + buf := [64]uint64{} + ctzList := [32]uint64{} + row := pkNRows - 32 + blockIdx := row / 64 + + // extract the 32x64 matrix + + tail := row % 64 + for i := 0; i < 32; i++ { + buf[i] = (mat[row+i][blockIdx+0] >> tail) | (mat[row+i][blockIdx+1] << (64 - tail)) + } + + // compute the column indices of pivots by Gaussian elimination. + // the indices are stored in ctz_list + + *pivots = 0 + + for i := 0; i < 32; i++ { + t := buf[i] + for j := i + 1; j < 32; j++ { + t |= buf[j] + } + if t == 0 { + return false // return if buf is not full rank + } + s := ctz(t) + ctzList[i] = uint64(s) + *pivots |= 1 << s + + for j := i + 1; j < 32; j++ { + mask := (buf[i] >> s) & 1 + mask -= 1 + buf[i] ^= buf[j] & mask + } + for j := i + 1; j < 32; j++ { + mask := (buf[j] >> s) & 1 + mask = -mask + buf[j] ^= buf[i] & mask + } + } + + // updating permutation + for j := 0; j < 32; j++ { + for k := j + 1; k < 64; k++ { + d := uint64(pi[row+j] ^ pi[row+k]) + d &= sameMask64(uint16(k), uint16(ctzList[j])) + pi[row+j] ^= int16(d) + pi[row+k] ^= int16(d) + } + } + + // moving columns of mat according to the column indices of pivots + for i := 0; i < pkNRows; i++ { + + t := (mat[i][blockIdx+0] >> tail) | (mat[i][blockIdx+1] << (64 - tail)) + + for j := 0; j < 32; j++ { + d := t >> j + d ^= t >> ctzList[j] + d &= 1 + + t ^= d << ctzList[j] + t ^= d << j + } + + mat[i][blockIdx+0] = (mat[i][blockIdx+0] & ((0xffffffffffffffff) >> (64 - tail))) | (t << tail) + mat[i][blockIdx+1] = (mat[i][blockIdx+1] & ((0xffffffffffffffff) << tail)) | (t >> (64 - tail)) + + } + + return true +} + +// 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{} + + // 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<> 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 < nblocksH; j++ { + for k := 0; k < gfBits; k++ { + mat[k][j] = prod[j][k] + } + } + + for i := 1; i < sysT; i++ { + for j := 0; j < nblocksH; j++ { + vecMul(&prod[j], &prod[j], &consts[j]) + for k := 0; k < gfBits; k++ { + mat[i*gfBits+k][j] = prod[j][k] + } + } + } + + // gaussian elimination + + for row := 0; row < pkNRows; row++ { + i := row >> 6 + j := row & 63 + + if row == pkNRows-32 { + if !movColumns(&mat, pi[:], pivots) { + return false + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[row][i] >> j + mask &= 1 + mask -= 1 + + for c := 0; c < nblocksH; c++ { + mat[row][c] ^= mat[k][c] & mask + } + + } + // return if not systematic + if ((mat[row][i] >> j) & 1) == 0 { + return false + } + + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + } + + pkp := pk[:] + + for i := 0; i < pkNRows; i++ { + + row := i + var k int + for k = blockIdx; k < nblocksH-1; k++ { + mat[row][k] = (mat[row][k] >> tail) | (mat[row][k+1] << (64 - tail)) + store8(pkp, mat[row][k]) + pkp = pkp[8:] + } + mat[row][k] >>= tail + storeI(pkp, mat[row][k], pkRowBytes%8) + pkp[(pkRowBytes%8)-1] &= (1 << (pkNCols % 8)) - 1 // removing redundant bits + pkp = pkp[pkRowBytes%8:] + + } + + return true +} diff --git a/kem/mceliece/mceliece6960119f/vec.go b/kem/mceliece/mceliece6960119f/vec.go new file mode 100644 index 000000000..1c5ce5f92 --- /dev/null +++ b/kem/mceliece/mceliece6960119f/vec.go @@ -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 mceliece6960119f + +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/kem/mceliece/mceliece8192128/benes.go b/kem/mceliece/mceliece8192128/benes.go new file mode 100644 index 000000000..d2c03a7ea --- /dev/null +++ b/kem/mceliece/mceliece8192128/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece8192128 + +// 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/kem/mceliece/mceliece8192128/fft.go b/kem/mceliece/mceliece8192128/fft.go new file mode 100644 index 000000000..fdb00e7d3 --- /dev/null +++ b/kem/mceliece/mceliece8192128/fft.go @@ -0,0 +1,215 @@ +// 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 mceliece8192128 + +import "github.com/cloudflare/circl/kem/mceliece/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 + } + + // adding the part contributed by x^128 + for i := 0; i < 128; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers8192[i][b] + } + } +} diff --git a/kem/mceliece/mceliece8192128/mceliece.go b/kem/mceliece/mceliece8192128/mceliece.go new file mode 100644 index 000000000..70a18519c --- /dev/null +++ b/kem/mceliece/mceliece8192128/mceliece.go @@ -0,0 +1,781 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece8192128 implements the IND-CCA2 secure key encapsulation mechanism +// mceliece8192128 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 mceliece8192128 + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e13" +) + +const ( + sysT = 128 // F(y) is 64 degree + gfBits = gf2e13.Bits + gfMask = gf2e13.Mask + unusedBits = 16 - gfBits + sysN = 8192 + 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 = 1357824 + PrivateKeySize = 14120 + CiphertextSize = 208 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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{} + bytes := [sysT * 2]byte{} + for { + rand(bytes[:]) + for i := 0; i < sysT; i++ { + ind[i] = loadGf(bytes[i*2:]) + } + // check for repetition + 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 := 0; i < sysN/8; i++ { + e[i] = 0 + + for j := 0; j < sysT; j++ { + mask := sameMask(uint16(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. +// 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+7] ^= product[i] + product[i-sysT+2] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece8192128" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece8192128/pk_gen.go b/kem/mceliece/mceliece8192128/pk_gen.go new file mode 100644 index 000000000..24612d994 --- /dev/null +++ b/kem/mceliece/mceliece8192128/pk_gen.go @@ -0,0 +1,267 @@ +// 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 mceliece8192128 + +import ( + "github.com/cloudflare/circl/kem/mceliece/internal" +) + +const exponent = 128 + +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) { + var ( + v0 uint64 + v1 uint64 + ) + irr := [sysT]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + for i := 0; i < gfBits; i++ { + for j := 63; j >= 0; j-- { + v0 <<= 1 + v1 <<= 1 + v0 |= uint64(irr[j]>>i) & 1 + v1 |= uint64(irr[j+64]>>i) & 1 + } + + out[0][i] = v0 + out[1][i] = v1 + } +} + +// 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 := [pkNCols / 64]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<> 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/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + for c := 0; c < pkNRows/64; c++ { + ops[row][c] = 0 + } + } + } + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + ops[row][i] = 1 + ops[row][i] <<= j + } + } + + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + + 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 i := pkNRows/64 - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + row := i*64 + j + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < pkNRows/64; 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/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + + for k := 0; k < pkNCols/64; k++ { + oneRow[k] = 0 + } + + for c := 0; c < pkNRows/64; c++ { + for d := 0; d < 64; d++ { + mask = ops[row][c] >> d + mask &= 1 + mask = -mask + + for k := 0; k < pkNCols/64; k++ { + oneRow[k] ^= mat[c*64+d][k+pkNRows/64] & mask + } + } + } + + for k := 0; k < pkNCols/64; k++ { + store8(pkp, oneRow[k]) + pkp = pkp[8:] + } + } + } + + return true +} diff --git a/kem/mceliece/mceliece8192128/vec.go b/kem/mceliece/mceliece8192128/vec.go new file mode 100644 index 000000000..901630cb5 --- /dev/null +++ b/kem/mceliece/mceliece8192128/vec.go @@ -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 mceliece8192128 + +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/kem/mceliece/mceliece8192128f/benes.go b/kem/mceliece/mceliece8192128f/benes.go new file mode 100644 index 000000000..eb9028aa5 --- /dev/null +++ b/kem/mceliece/mceliece8192128f/benes.go @@ -0,0 +1,133 @@ +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package mceliece8192128f + +// 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/kem/mceliece/mceliece8192128f/fft.go b/kem/mceliece/mceliece8192128f/fft.go new file mode 100644 index 000000000..95e45ac54 --- /dev/null +++ b/kem/mceliece/mceliece8192128f/fft.go @@ -0,0 +1,215 @@ +// 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 mceliece8192128f + +import "github.com/cloudflare/circl/kem/mceliece/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 + } + + // adding the part contributed by x^128 + for i := 0; i < 128; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers8192[i][b] + } + } +} diff --git a/kem/mceliece/mceliece8192128f/mceliece.go b/kem/mceliece/mceliece8192128f/mceliece.go new file mode 100644 index 000000000..7203b56dd --- /dev/null +++ b/kem/mceliece/mceliece8192128f/mceliece.go @@ -0,0 +1,781 @@ +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package mceliece8192128f implements the IND-CCA2 secure key encapsulation mechanism +// mceliece8192128f 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 mceliece8192128f + +import ( + "bytes" + cryptoRand "crypto/rand" + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/kem/mceliece/internal" + "github.com/cloudflare/circl/math/gf2e13" +) + +const ( + sysT = 128 // F(y) is 64 degree + gfBits = gf2e13.Bits + gfMask = gf2e13.Mask + unusedBits = 16 - gfBits + sysN = 8192 + 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 = 1357824 + PrivateKeySize = 14120 + CiphertextSize = 208 + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +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<>= 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 + } + + return nil +} + +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} + +// 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{} + bytes := [sysT * 2]byte{} + for { + rand(bytes[:]) + for i := 0; i < sysT; i++ { + ind[i] = loadGf(bytes[i*2:]) + } + // check for repetition + 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 := 0; i < sysN/8; i++ { + e[i] = 0 + + for j := 0; j < sysT; j++ { + mask := sameMask(uint16(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. +// 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+7] ^= product[i] + product[i-sysT+2] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= 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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "mceliece8192128f" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/mceliece8192128f/pk_gen.go b/kem/mceliece/mceliece8192128f/pk_gen.go new file mode 100644 index 000000000..2af05122e --- /dev/null +++ b/kem/mceliece/mceliece8192128f/pk_gen.go @@ -0,0 +1,300 @@ +// 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 mceliece8192128f + +import ( + "github.com/cloudflare/circl/kem/mceliece/internal" +) + +const exponent = 128 + +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) { + var ( + v0 uint64 + v1 uint64 + ) + irr := [sysT]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + for i := 0; i < gfBits; i++ { + for j := 63; j >= 0; j-- { + v0 <<= 1 + v1 <<= 1 + v0 |= uint64(irr[j]>>i) & 1 + v1 |= uint64(irr[j+64]>>i) & 1 + } + + out[0][i] = v0 + out[1][i] = v1 + } +} + +// Return number of trailing zeros of the non-zero input `input` +func ctz(in uint64) int { + m := 0 + r := 0 + for i := 0; i < 64; i++ { + b := int((in >> i) & 1) + m |= b + r += (m ^ 1) & (b ^ 1) + } + return r +} + +// Takes two 16-bit integers and determines whether they are equal (all bits set) or different (0) +func sameMask64(x, y uint16) uint64 { + mask := uint64(x ^ y) + mask -= 1 + mask >>= 63 + mask = -mask + return mask +} + +// Move columns in matrix `mat` +func movColumns(mat *[pkNRows][(sysN + 63) / 64]uint64, pi []int16, pivots *uint64) bool { + buf := [64]uint64{} + ctzList := [32]uint64{} + row := pkNRows - 32 + blockIdx := row / 64 + + // extract the 32x64 matrix + + for i := 0; i < 32; i++ { + buf[i] = (mat[row+i][blockIdx+0] >> 32) | (mat[row+i][blockIdx+1] << 32) + } + + // compute the column indices of pivots by Gaussian elimination. + // the indices are stored in ctz_list + + *pivots = 0 + + for i := 0; i < 32; i++ { + t := buf[i] + for j := i + 1; j < 32; j++ { + t |= buf[j] + } + if t == 0 { + return false // return if buf is not full rank + } + s := ctz(t) + ctzList[i] = uint64(s) + *pivots |= 1 << s + + for j := i + 1; j < 32; j++ { + mask := (buf[i] >> s) & 1 + mask -= 1 + buf[i] ^= buf[j] & mask + } + for j := i + 1; j < 32; j++ { + mask := (buf[j] >> s) & 1 + mask = -mask + buf[j] ^= buf[i] & mask + } + } + + // updating permutation + for j := 0; j < 32; j++ { + for k := j + 1; k < 64; k++ { + d := uint64(pi[row+j] ^ pi[row+k]) + d &= sameMask64(uint16(k), uint16(ctzList[j])) + pi[row+j] ^= int16(d) + pi[row+k] ^= int16(d) + } + } + + // moving columns of mat according to the column indices of pivots + for i := 0; i < pkNRows; i++ { + + t := (mat[i][blockIdx+0] >> 32) | (mat[i][blockIdx+1] << 32) + + for j := 0; j < 32; j++ { + d := t >> j + d ^= t >> ctzList[j] + d &= 1 + + t ^= d << ctzList[j] + t ^= d << j + } + + mat[i][blockIdx+0] = (mat[i][blockIdx+0] << 32 >> 32) | (t << 32) + mat[i][blockIdx+1] = (mat[i][blockIdx+1] >> 32 << 32) | (t >> 32) + + } + + return true +} + +// 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{} + + // 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<> 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 < nblocksH; j++ { + for k := 0; k < gfBits; k++ { + mat[k][j] = prod[j][k] + } + } + + for i := 1; i < sysT; i++ { + for j := 0; j < nblocksH; j++ { + vecMul(&prod[j], &prod[j], &consts[j]) + for k := 0; k < gfBits; k++ { + mat[i*gfBits+k][j] = prod[j][k] + } + } + } + + // gaussian elimination + + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + + if row == pkNRows-32 { + if !movColumns(&mat, pi[:], pivots) { + return false + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[row][i] >> j + mask &= 1 + mask -= 1 + + for c := 0; c < nblocksH; c++ { + mat[row][c] ^= mat[k][c] & mask + } + + } + // return if not systematic + if ((mat[row][i] >> j) & 1) == 0 { + return false + } + + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + + for k := row + 1; k < pkNRows; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + } + } + + pkp := pk[:] + + for i := 0; i < pkNRows; i++ { + for j := nblocksI; j < nblocksH; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + } + + return true +} diff --git a/kem/mceliece/mceliece8192128f/vec.go b/kem/mceliece/mceliece8192128f/vec.go new file mode 100644 index 000000000..3f95b744e --- /dev/null +++ b/kem/mceliece/mceliece8192128f/vec.go @@ -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 mceliece8192128f + +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/kem/mceliece/templates/benes_348864.templ.go b/kem/mceliece/templates/benes_348864.templ.go new file mode 100644 index 000000000..c6230a40f --- /dev/null +++ b/kem/mceliece/templates/benes_348864.templ.go @@ -0,0 +1,75 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// Code generated from benes_348864.templ.go. DO NOT EDIT. + +package {{.Pkg}} + +// Layers of the Beneš network. The required size of `data` and `bits` depends on the value `lgs`. +func layer(data, bits []uint64, lgs int) { + index := 0 + s := 1 << lgs + for i := 0; i < 64; i += s * 2 { + for j := i; j < i+s; j++ { + d := data[j] ^ data[j+s] + d &= bits[index] + index++ + data[j] ^= d + data[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 *[512]byte, bits *[condBytes]byte) { + bs := [64]uint64{} + cond := [64]uint64{} + for i := 0; i < 64; i++ { + bs[i] = load8(r[i*8:]) + } + + transpose64x64(&bs, &bs) + + for low := 0; low <= 5; low++ { + for i := 0; i < 64; i++ { + cond[i] = uint64(load4(bits[low*256+i*4:])) + } + transpose64x64(&cond, &cond) + layer(bs[:], cond[:], low) + } + + transpose64x64(&bs, &bs) + + for low := 0; low <= 5; low++ { + for i := 0; i < 32; i++ { + cond[i] = load8(bits[(low+6)*256+i*8:]) + } + layer(bs[:], cond[:], low) + } + for low := 4; low >= 0; low-- { + for i := 0; i < 32; i++ { + cond[i] = load8(bits[(4-low+6+6)*256+i*8:]) + } + layer(bs[:], cond[:], low) + } + + transpose64x64(&bs, &bs) + + for low := 5; low >= 0; low-- { + for i := 0; i < 64; i++ { + cond[i] = uint64(load4(bits[(5-low+6+6+5)*256+i*4:])) + } + transpose64x64(&cond, &cond) + layer(bs[:], cond[:], low) + } + transpose64x64(&bs, &bs) + + for i := 0; i < 64; i++ { + store8(r[i*8:], bs[i]) + } +} diff --git a/kem/mceliece/templates/benes_other.templ.go b/kem/mceliece/templates/benes_other.templ.go new file mode 100644 index 000000000..2d0337f4f --- /dev/null +++ b/kem/mceliece/templates/benes_other.templ.go @@ -0,0 +1,137 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// Code generated from benes_other.templ.go. DO NOT EDIT. + +package {{.Pkg}} + +// 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/kem/mceliece/templates/fft_348864.templ.go b/kem/mceliece/templates/fft_348864.templ.go new file mode 100644 index 000000000..b69e4fc29 --- /dev/null +++ b/kem/mceliece/templates/fft_348864.templ.go @@ -0,0 +1,69 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// Code generated from fft_348864.templ.go. DO NOT EDIT. + +// The following code is translated from the C `vec` Additional Implementation +// from the NIST round 4 submission package. + +package {{.Pkg}} + +import "github.com/cloudflare/circl/kem/mceliece/internal" + +func fft(out *[exponent][gfBits]uint64, in *[gfBits]uint64) { + radixConversions(in) + butterflies(out, in) +} + +func radixConversions(in *[gfBits]uint64) { + for j := 0; j <= 4; j++ { + for i := 0; i < gfBits; i++ { + for k := 4; k >= j; k-- { + in[i] ^= (in[i] & internal.RadixConversionsMask[k][0]) >> (1 << k) + in[i] ^= (in[i] & internal.RadixConversionsMask[k][1]) >> (1 << k) + } + } + + vecMul(in, in, &internal.RadixConversionsS4096[j]) // scaling + } +} + +func butterflies(out *[exponent][gfBits]uint64, in *[gfBits]uint64) { + tmp := [gfBits]uint64{} + var constsPtr int + // broadcast + for j := 0; j < 64; j++ { + for i := 0; i < gfBits; i++ { + out[j][i] = (in[i] >> internal.ButterfliesReversal4096[j]) & 1 + out[j][i] = -out[j][i] + } + } + + // butterflies + for i := 0; i <= 5; i++ { + s := 1 << i + + for j := 0; j < 64; j += 2 * s { + for k := j; k < j+s; k++ { + vecMul(&tmp, &out[k+s], &internal.ButterfliesConsts4096[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 + } + + // adding the part contributed by x^64 + for i := 0; i < 64; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers4096[i][b] + } + } +} diff --git a/kem/mceliece/templates/fft_other.templ.go b/kem/mceliece/templates/fft_other.templ.go new file mode 100644 index 000000000..c54c1f390 --- /dev/null +++ b/kem/mceliece/templates/fft_other.templ.go @@ -0,0 +1,221 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// 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 {{.Pkg}} + +import "github.com/cloudflare/circl/kem/mceliece/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 + } + + {{ if or .Is6688128 .Is8192128 }} + // adding the part contributed by x^128 + for i := 0; i < 128; i++ { + for b := 0; b < gfBits; b++ { + out[i][b] ^= internal.Powers8192[i][b] + } + } + {{end}} +} \ No newline at end of file diff --git a/kem/mceliece/templates/mceliece.templ.go b/kem/mceliece/templates/mceliece.templ.go new file mode 100644 index 000000000..e308ac5c9 --- /dev/null +++ b/kem/mceliece/templates/mceliece.templ.go @@ -0,0 +1,896 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// Code generated from mceliece.templ.go. DO NOT EDIT. + +// Package {{.Pkg}} implements the IND-CCA2 secure key encapsulation mechanism +// {{.Pkg}} 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 {{.Pkg}} + +import ( + "bytes" + cryptoRand "crypto/rand" + {{if .Is6960119}} "fmt" {{end}} + "io" + + "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/internal/sha3" + "github.com/cloudflare/circl/kem" + "github.com/cloudflare/circl/math/{{.Param.Gf}}" + "github.com/cloudflare/circl/kem/mceliece/internal" +) + +const ( + sysT = {{.Param.SysT}}// F(y) is 64 degree + gfBits = {{.Param.Gf}}.Bits + gfMask = {{.Param.Gf}}.Mask + unusedBits = 16 - gfBits + sysN = {{.Param.SysN}} + 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 = {{.Param.PublicKeySize}} + PrivateKeySize = {{.Param.PrivateKeySize}} + CiphertextSize = {{.Param.CiphertextSize}} + SharedKeySize = 32 + seedSize = 32 + encapsulationSeedSize = 48 +) + +type PublicKey struct { + pk [PublicKeySize]byte +} + +type PrivateKey struct { + sk [PrivateKeySize]byte +} + +type ( + gf = {{.Param.Gf}}.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<>= 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 + } + + {{if not .Is6960119}} + return nil + {{else}} + // 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) + {{end}} +} + +{{if not .Is6960119}} +// 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{} + var b byte + + 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] + } + + row[i/8] |= 1 << (i % 8) + + b = 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) + } +} +{{end}} + +{{if .Is8192128}} +// 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{} + bytes := [sysT * 2]byte{} + for { + rand(bytes[:]) + for i := 0; i < sysT; i++ { + ind[i] = loadGf(bytes[i*2:]) + } + // check for repetition + 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 := 0; i < sysN/8; i++ { + e[i] = 0 + + for j := 0; j < sysT; j++ { + mask := sameMask(uint16(i), (ind[j] >> 3)) + e[i] |= val[j] & mask + } + } + return nil +} +{{else}} +// 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 +} +{{end}} + +// 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 := {{.Param.Gf}}.Inv({{.Param.Gf}}.Mul(e, e)) + for j := 0; j < 2*sysT; j++ { + out[j] = {{.Param.Gf}}.Add(out[j], {{.Param.Gf}}.Mul(eInv, c)) + eInv = {{.Param.Gf}}.Mul(eInv, L[i]) + } + } +} + +func min(a, b int) int { + if a > b { + return b + } + return a +} + +// The Berlekamp-Massey algorithm. +// 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 ^= {{.Param.Gf}}.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 = {{.Param.Gf}}.Div(d, b) + for i := 0; i <= sysT; i++ { + C[i] ^= {{.Param.Gf}}.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 := {{.Param.Gf}}.Inv(mat[j][j]) + for c := 0; c <= sysT; c++ { + mat[c][j] = {{.Param.Gf}}.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] ^= {{.Param.Gf}}.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] ^= {{.Param.Gf}}.Mul(a[i], b[j]) + } + } + + for i := (sysT - 1) * 2; i >= sysT; i-- { + // polynomial reduction + {{if .Is348864}} + product[i-sysT+3] ^= product[i] + product[i-sysT+1] ^= product[i] + product[i-sysT] ^= {{.Param.Gf}}.Mul(product[i], 2) + {{else if .Is460896}} + product[i-sysT+10] ^= product[i] + product[i-sysT+9] ^= product[i] + product[i-sysT+6] ^= product[i] + product[i-sysT] ^= product[i] + {{else if .Is6960119}} + product[i-sysT+8] ^= product[i] + product[i-sysT+0] ^= product[i] + {{else}} + product[i-sysT+7] ^= product[i]; + product[i-sysT+2] ^= product[i]; + product[i-sysT+1] ^= product[i]; + product[i-sysT] ^= product[i]; + {{end}} + } + + 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 = {{.Param.Gf}}.Mul(r, a) + r = {{.Param.Gf}}.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 +} + +type scheme struct{} + +var sch kem.Scheme = &scheme{} + +// Scheme returns a KEM interface. +func Scheme() kem.Scheme { return sch } + +func (*scheme) Name() string { return "{{.Name}}" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SeedSize() int { return seedSize } +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 +} + +// 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) 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 { + pk, _ := sch.DeriveKeyPair(sk.MarshalCompressedBinary()) + return 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) { + 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 (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { + if len(seed) != seedSize { + panic("seed must be of length EncapsulationSeedSize") + } + return deriveKeyPair(seed) +} + +func encapsulate(pk kem.PublicKey, rand randFunc) (ct, ss []byte, err error) { + ppk, ok := pk.(*PublicKey) + if !ok { + return nil, nil, kem.ErrTypeMismatch + } + + ciphertext := [CiphertextSize]byte{} + sharedSecret := [SharedKeySize]byte{} + err = kemEncapsulate(&ciphertext, &sharedSecret, &ppk.pk, rand) + if err != nil { + return nil, nil, err + } + return ciphertext[:], sharedSecret[:], nil +} + +func (*scheme) Encapsulate(pk kem.PublicKey) (ct, ss []byte, err error) { + return encapsulate(pk, func(pool []byte) error { + _, err2 := io.ReadFull(cryptoRand.Reader, pool) + return err2 + }) +} + +func (*scheme) EncapsulateDeterministically(pk kem.PublicKey, seed []byte) (ct, ss []byte, err error) { + // This follow test standards + if len(seed) != encapsulationSeedSize { + return nil, nil, kem.ErrSeedSize + } + + entropy := [48]byte{} + waste := [32]byte{} + copy(entropy[:], seed) + dRng := nist.NewDRBG(&entropy) + dRng.Fill(waste[:]) + + return encapsulate(pk, func(pool []byte) error { + dRng.Fill(pool) + return 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{} + err := kemDecapsulate(&ss, (*[CiphertextSize]byte)(ct), &ssk.sk) + if err != nil { + return nil, err + } + 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/kem/mceliece/templates/operations_6960119.templ.go b/kem/mceliece/templates/operations_6960119.templ.go new file mode 100644 index 000000000..e1f8a21a1 --- /dev/null +++ b/kem/mceliece/templates/operations_6960119.templ.go @@ -0,0 +1,61 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// Code generated from operations_6960119.templ.go. DO NOT EDIT. + +package {{.Pkg}} + +// 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) + } +} \ No newline at end of file diff --git a/kem/mceliece/templates/pk_gen_vec.templ.go b/kem/mceliece/templates/pk_gen_vec.templ.go new file mode 100644 index 000000000..cdf8685dc --- /dev/null +++ b/kem/mceliece/templates/pk_gen_vec.templ.go @@ -0,0 +1,608 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// 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 {{.Pkg}} + +import ( + "github.com/cloudflare/circl/kem/mceliece/internal" +) + +{{ if .Is348864 }} +const exponent = 64 +{{ else }} +const exponent = 128 +{{ end }} + +{{ if not .Is8192128 }} +func storeI(out []byte, in uint64, i int) { + for j := 0; j < i; j++ { + out[j] = byte((in >> (j * 8)) & 0xFF) + } +} +{{end}} + +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 + } + } + } +} + +{{ if or .Is6688128 .Is8192128 }} +func irrLoad(out *[2][gfBits]uint64, in []byte) { + var ( + v0 uint64 + v1 uint64 + ) + irr := [sysT]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + for i := 0; i < gfBits; i++ { + for j := 63; j >= 0; j-- { + v0 <<= 1 + v1 <<= 1 + v0 |= uint64(irr[j]>>i) & 1 + v1 |= uint64(irr[j+64]>>i) & 1 + } + + out[0][i] = v0 + out[1][i] = v1 + } +} +{{else}} +{{ if .Is348864 }} +func irrLoad(out *[gfBits]uint64, in []byte) { +{{else}} +func irrLoad(out *[2][gfBits]uint64, in []byte) { +{{end}} + irr := [sysT + 1]uint16{} + + for i := 0; i < sysT; i++ { + irr[i] = loadGf(in[i*2:]) + } + + irr[sysT] = 1 + {{ if .Is348864 }} + for i := 0; i < gfBits; i++ { + out[i] = 0; + } + + for i := sysT; i >= 0; i-- { + for j := 0; j < gfBits; j++ { + out[j] <<= 1; + out[j] |= uint64(irr[i] >> j) & 1; + } + } + {{ else }} + 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] + } + {{ end }} +} +{{end}} + + +{{if .IsSemiSystematic}} +// Return number of trailing zeros of the non-zero input `input` +func ctz(in uint64) int { + m := 0 + r := 0 + for i := 0; i < 64; i++ { + b := int((in >> i) & 1) + m |= b + r += (m ^ 1) & (b ^ 1) + } + return r +} + +// Takes two 16-bit integers and determines whether they are equal (all bits set) or different (0) +func sameMask64(x, y uint16) uint64 { + mask := uint64(x ^ y) + mask -= 1 + mask >>= 63 + mask = -mask + return mask +} + +// Move columns in matrix `mat` +func movColumns(mat *[pkNRows][(sysN + 63) / 64]uint64, pi []int16, pivots *uint64) bool { + buf := [64]uint64{} + ctzList := [32]uint64{} + row := pkNRows - 32 + blockIdx := row / 64 + + // extract the 32x64 matrix + {{if .Is6960119}} + tail := row % 64 + for i := 0; i < 32; i++ { + buf[i] = (mat[row+i][blockIdx+0] >> tail) | (mat[row+i][blockIdx+1] << (64-tail)) + } + {{else}} + for i := 0; i < 32; i++ { + {{if or .Is8192128 .Is6688128 .Is348864}} + buf[i] = (mat[row+i][blockIdx+0] >> 32) | (mat[row+i][blockIdx+1] << 32) + {{else}} + buf[i] = mat[row+i][blockIdx] + {{end}} + } + {{end}} + + // compute the column indices of pivots by Gaussian elimination. + // the indices are stored in ctz_list + + *pivots = 0 + + for i := 0; i < 32; i++ { + t := buf[i] + for j := i + 1; j < 32; j++ { + t |= buf[j] + } + if t == 0 { + return false // return if buf is not full rank + } + s := ctz(t) + ctzList[i] = uint64(s) + *pivots |= 1 << s + + for j := i + 1; j < 32; j++ { + mask := (buf[i] >> s) & 1 + mask -= 1 + buf[i] ^= buf[j] & mask + } + for j := i + 1; j < 32; j++ { + mask := (buf[j] >> s) & 1 + mask = -mask + buf[j] ^= buf[i] & mask + } + } + + // updating permutation + for j := 0; j < 32; j++ { + for k := j + 1; k < 64; k++ { + d := uint64(pi[row+j] ^ pi[row+k]) + d &= sameMask64(uint16(k), uint16(ctzList[j])) {{ if .Is348864 }} & 0xFFFF {{ end }} + pi[row+j] ^= int16(d) + pi[row+k] ^= int16(d) + } + } + + // moving columns of mat according to the column indices of pivots + for i := 0; i < pkNRows; i++ { + {{if .Is6960119}} + t := (mat[i][blockIdx+0] >> tail) | (mat[i][blockIdx+1] << (64-tail)) + {{else if or .Is8192128 .Is6688128 .Is348864}} + t := (mat[i][blockIdx+0] >> 32) | (mat[i][blockIdx+1] << 32) + {{else}} + t := mat[i][blockIdx] + {{end}} + + for j := 0; j < 32; j++ { + d := t >> j + d ^= t >> ctzList[j] + d &= 1 + + t ^= d << ctzList[j] + t ^= d << j + } + + {{if or .Is8192128 .Is6688128 .Is348864}} + mat[i][blockIdx+0] = (mat[i][blockIdx+0] << 32 >> 32) | (t << 32) + mat[i][blockIdx+1] = (mat[i][blockIdx+1] >> 32 << 32) | (t >> 32) + {{else if .Is6960119}} + mat[i][blockIdx+0] = (mat[i][blockIdx+0] & ((0xffffffffffffffff) >> (64-tail))) | (t << tail); + mat[i][blockIdx+1] = (mat[i][blockIdx+1] & ((0xffffffffffffffff) << tail)) | (t >> (64-tail)); + {{else}} + mat[i][blockIdx] = t + {{end}} + } + + return true +} +{{end}} + + +// 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 + {{ if or .Is348864 .Is6688128 }} + blockIdx = nblocksI + {{ else }} + blockIdx = nblocksI - 1 + tail = pkNRows % 64 + {{ end }} + ) + mat := [pkNRows][nblocksH]uint64{} + var mask uint64 + {{ if .Is348864 }} + irrInt := [gfBits]uint64{} + {{ else }} + irrInt := [2][gfBits]uint64{} + {{ end }} + consts := [exponent][gfBits]uint64{} + eval := [exponent][gfBits]uint64{} + prod := [exponent][gfBits]uint64{} + tmp := [gfBits]uint64{} + list := [1 << gfBits]uint64{} + {{if not .IsSemiSystematic}} + ops := [pkNRows][nblocksI]uint64{} + {{ if .Is8192128 }} + oneRow := [pkNCols / 64]uint64{} + {{ else }} + oneRow := [exponent]uint64{} + {{ end }} + {{ end }} + + // 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<> 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 < {{if .IsSemiSystematic}} nblocksH {{else}} nblocksI {{end}}; j++ { + for k := 0; k < gfBits; k++ { + mat[k][j] = prod[j][k] + } + } + + for i := 1; i < sysT; i++ { + for j := 0; j < {{if .IsSemiSystematic}} nblocksH {{else}} nblocksI {{end}}; j++ { + vecMul(&prod[j], &prod[j], &consts[j]) + for k := 0; k < gfBits; k++ { + mat[i*gfBits+k][j] = prod[j][k] + } + } + } + + {{if .IsSemiSystematic}} + // gaussian elimination + {{else}} + // gaussian elimination to obtain an upper triangular matrix + // and keep track of the operations in ops + {{ if .Is8192128 }} + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + for c := 0; c < pkNRows/64; c++ { + ops[row][c] = 0 + } + } + } + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + ops[row][i] = 1 + ops[row][i] <<= j + } + } + {{ else }} + 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) + } + + {{ if not (or .Is348864 .Is6688128) }} + column := [pkNRows]uint64{} + for i := 0; i < pkNRows; i++ { + column[i] = mat[i][blockIdx] + } + {{ end }} + {{ end }} + {{ end }} + + + {{ if .Is8192128 }} + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + {{ else }} + for row := 0; row < pkNRows; row++ { + i := row >> 6 + j := row & 63 + {{ end }} + + {{if .IsSemiSystematic}} + if row == pkNRows-32 { + if !movColumns(&mat, pi[:], pivots) { + return false + } + } + {{end}} + + for k := row + 1; k < pkNRows; k++ { + mask = mat[row][i] >> j + mask &= 1 + mask -= 1 + + + {{if .IsSemiSystematic}} + for c := 0; c < nblocksH; c++ { + mat[row][c] ^= mat[k][c] & mask + } + {{else}} + for c := 0; c < nblocksI; c++ { + mat[row][c] ^= mat[k][c] & mask + ops[row][c] ^= ops[k][c] & mask + } + {{end}} + } + // return if not systematic + if ((mat[row][i] >> j) & 1) == 0 { + return false + } + + {{if .IsSemiSystematic}} + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < nblocksH; c++ { + mat[k][c] ^= mat[row][c] & mask + } + } + {{end}} + + for k := row + 1; k < pkNRows; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < {{if .IsSemiSystematic}}nblocksH {{else}} nblocksI {{end}}; c++ { + mat[k][c] ^= mat[row][c] & mask + {{if not .IsSemiSystematic}} + ops[k][c] ^= ops[row][c] & mask + {{end}} + } + } + } + {{ if .Is8192128 }} + } + {{ end }} + + + pkp := pk[:] + {{if .IsSemiSystematic}} + for i := 0; i < pkNRows; i++ { + {{ if .Is460896 }} + storeI(pkp, mat[i][nblocksI-1]>>tail, (64-tail)/8) + pkp = pkp[(64-tail)/8:] + for j := nblocksI; j < nblocksH; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + {{ else if or .Is348864 .Is6688128 }} + var j int + for j = nblocksI; j < nblocksH-1; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + storeI(pkp, mat[i][j], pkRowBytes%8) + pkp = pkp[pkRowBytes%8:] + {{ else if .Is6960119 }} + row := i + var k int + for k = blockIdx; k < nblocksH-1; k++ { + mat[row][k] = (mat[row][k] >> tail) | (mat[row][k+1] << (64-tail)) + store8(pkp, mat[row][k]) + pkp = pkp[8:] + } + mat[row][k] >>= tail + storeI(pkp, mat[row][k], pkRowBytes%8) + pkp[(pkRowBytes%8)-1] &= (1 << (pkNCols % 8)) - 1 // removing redundant bits + pkp = pkp[pkRowBytes%8:] + {{ else if .Is8192128 }} + for j := nblocksI; j < nblocksH; j++ { + store8(pkp, mat[i][j]) + pkp = pkp[8:] + } + {{ end }} + } + {{else}} + // computing the lineaer map required to obatin the systematic form + {{ if .Is8192128 }} + for i := pkNRows/64 - 1; i >= 0; i-- { + for j := 63; j >= 0; j-- { + row := i*64 + j + for k := 0; k < row; k++ { + mask = mat[k][i] >> j + mask &= 1 + mask = -mask + + for c := 0; c < pkNRows/64; c++ { + ops[k][c] ^= ops[row][c] & mask + } + } + } + } + {{else}} + 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 + } + } + } + {{end}} + + // 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] + } + } + } + + {{ if .Is8192128 }} + for i := 0; i < pkNRows/64; i++ { + for j := 0; j < 64; j++ { + row := i*64 + j + + for k := 0; k < pkNCols/64; k++ { + oneRow[k] = 0 + } + + for c := 0; c < pkNRows/64; c++ { + for d := 0; d < 64; d++ { + mask = ops[row][c] >> d + mask &= 1 + mask = -mask + + for k := 0; k < pkNCols/64; k++ { + oneRow[k] ^= mat[c*64+d][k+pkNRows/64] & mask + } + } + } + + for k := 0; k < pkNCols/64; k++ { + store8(pkp, oneRow[k]) + pkp = pkp[8:] + } + } + } + {{ else }} + {{ if not (or .Is348864 .Is6688128) }} + for i := 0; i < pkNRows; i++ { + mat[i][blockIdx] = column[i] + } + {{end}} + 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++ { + {{ if not (or .Is348864 .Is6688128) }} + oneRow[k] = (oneRow[k] >> tail) | (oneRow[k+1] << (64 - tail)) + {{end}} + store8(pkp, oneRow[k]) + pkp = pkp[8:] + } + + {{ if not (or .Is348864 .Is6688128) }} + oneRow[k] >>= tail + {{end}} + storeI(pkp, oneRow[k], pkRowBytes%8) + + {{if .Is6960119}} + pkp[(pkRowBytes%8)-1] &= (1 << (pkNCols % 8)) - 1 // removing redundant bits + {{end}} + + pkp = pkp[pkRowBytes%8:] + } + {{ end }} + {{ end }} + return true +} diff --git a/kem/mceliece/templates/vec.templ.go b/kem/mceliece/templates/vec.templ.go new file mode 100644 index 000000000..681012574 --- /dev/null +++ b/kem/mceliece/templates/vec.templ.go @@ -0,0 +1,165 @@ +// +build ignore +// The previous line (and this one up to the warning below) is removed by the +// template generator. + +// 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 {{.Pkg}} + +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-- { + {{ if .Is348864 }} + buf[i-gfBits+3] ^= buf[i] + buf[i-gfBits+0] ^= buf[i] + {{ else }} + buf[i-gfBits+4] ^= buf[i] + buf[i-gfBits+3] ^= buf[i] + buf[i-gfBits+1] ^= buf[i] + buf[i-gfBits+0] ^= buf[i] + {{ end }} + } + + for i := 0; i < gfBits; i++ { + h[i] = buf[i] + } +} + +// bitsliced field squarings +func vecSq(out, in *[gfBits]uint64) { + result := [gfBits]uint64{} + + {{ if .Is348864 }} + result[0] = in[0] ^ in[6] + result[1] = in[11] + result[2] = in[1] ^ in[7] + result[3] = in[6] + result[4] = in[2] ^ in[11] ^ in[8] + result[5] = in[7] + result[6] = in[3] ^ in[9] + result[7] = in[8] + result[8] = in[4] ^ in[10] + result[9] = in[9] + result[10] = in[5] ^ in[11] + result[11] = in[10] + {{ else }} + 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 + {{ end }} + + 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 + + {{ if .Is348864 }} + vecSq(out, out); + vecSq(out, out); + vecMul(out, out, &tmp11); // 1111111111 + + vecSq(out, out); + vecMul(out, out, in); // 11111111111 + + vecSq(out, out); // 111111111110 + {{ else }} + vecSq(out, out) + vecSq(out, out) + vecSq(out, out) + vecSq(out, out) + vecMul(out, out, &tmp1111) // ^111111111111 + + vecSq(out, out) // ^1111111111110 + {{ end }} +} + +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/kem/mceliece/testdata/testdata.go b/kem/mceliece/testdata/testdata.go new file mode 100644 index 000000000..4c05cba76 --- /dev/null +++ b/kem/mceliece/testdata/testdata.go @@ -0,0 +1,130 @@ +package testdata + +import ( + "bufio" + "compress/bzip2" + "encoding/base64" + "encoding/binary" + "errors" + "fmt" + "io" + "os" + "strings" +) + +func FindTestDataByte(searchKey, path string) ([]byte, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + + reader := bufio.NewReader(bzip2.NewReader(file)) + for { + line, err := reader.ReadString('\n') + if err == io.EOF { + return nil, fmt.Errorf("key %s not found", searchKey) + } + if err != nil { + return nil, err + } + + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "#") || line == "" { + continue + } + + var key, value string + for i, v := range strings.Split(line, "=") { + switch i { + case 0: + key = strings.TrimSpace(v) + case 1: + value = strings.TrimSpace(v) + default: + break + } + } + + if value == "" { + return nil, fmt.Errorf("value is nil for key %s", key) + } + + if key != searchKey { + continue + } + + data, err := base64.RawStdEncoding.DecodeString(value) + return data, err + } +} + +func FindTestDataU16(searchKey, path string) ([]uint16, error) { + data, err := FindTestDataByte(searchKey, path) + if err != nil { + return nil, err + } + + if len(data)%2 != 0 { + return nil, errors.New("data length does not align") + } + + out := make([]uint16, len(data)/2) + for i := 0; i < len(out); i++ { + out[i] = binary.BigEndian.Uint16(data) + data = data[2:] + } + + return out, nil +} + +func FindTestDataI16(searchKey, path string) ([]int16, error) { + data, err := FindTestDataU16(searchKey, path) + if err != nil { + return nil, err + } + + out := make([]int16, len(data)) + for i := 0; i < len(out); i++ { + out[i] = int16(data[i]) + } + + return out, nil +} + +func FindTestDataU32(searchKey, path string) ([]uint32, error) { + data, err := FindTestDataByte(searchKey, path) + if err != nil { + return nil, err + } + + if len(data)%4 != 0 { + return nil, errors.New("data length does not align") + } + + out := make([]uint32, len(data)/4) + for i := 0; i < len(out); i += 4 { + out[i] = binary.BigEndian.Uint32(data) + data = data[4:] + } + + return out, nil +} + +func FindTestDataU64(searchKey, path string) ([]uint64, error) { + data, err := FindTestDataByte(searchKey, path) + if err != nil { + return nil, err + } + + if len(data)%8 != 0 { + return nil, errors.New("data length does not align") + } + + out := make([]uint64, len(data)/8) + for i := 0; i < len(out); i++ { + out[i] = binary.BigEndian.Uint64(data) + data = data[8:] + } + + return out, nil +} diff --git a/kem/mceliece/testdata/testdata.txt.bz2 b/kem/mceliece/testdata/testdata.txt.bz2 new file mode 100644 index 000000000..8ef1ab18d Binary files /dev/null and b/kem/mceliece/testdata/testdata.txt.bz2 differ diff --git a/kem/schemes/schemes.go b/kem/schemes/schemes.go index c6c3c4a32..ab1dca92f 100644 --- a/kem/schemes/schemes.go +++ b/kem/schemes/schemes.go @@ -26,6 +26,16 @@ import ( "github.com/cloudflare/circl/kem/kyber/kyber1024" "github.com/cloudflare/circl/kem/kyber/kyber512" "github.com/cloudflare/circl/kem/kyber/kyber768" + "github.com/cloudflare/circl/kem/mceliece/mceliece348864" + "github.com/cloudflare/circl/kem/mceliece/mceliece348864f" + "github.com/cloudflare/circl/kem/mceliece/mceliece460896" + "github.com/cloudflare/circl/kem/mceliece/mceliece460896f" + "github.com/cloudflare/circl/kem/mceliece/mceliece6688128" + "github.com/cloudflare/circl/kem/mceliece/mceliece6688128f" + "github.com/cloudflare/circl/kem/mceliece/mceliece6960119" + "github.com/cloudflare/circl/kem/mceliece/mceliece6960119f" + "github.com/cloudflare/circl/kem/mceliece/mceliece8192128" + "github.com/cloudflare/circl/kem/mceliece/mceliece8192128f" ) var allSchemes = [...]kem.Scheme{ @@ -38,6 +48,16 @@ var allSchemes = [...]kem.Scheme{ kyber512.Scheme(), kyber768.Scheme(), kyber1024.Scheme(), + mceliece348864.Scheme(), + mceliece348864f.Scheme(), + mceliece460896.Scheme(), + mceliece460896f.Scheme(), + mceliece6688128.Scheme(), + mceliece6688128f.Scheme(), + mceliece6960119.Scheme(), + mceliece6960119f.Scheme(), + mceliece8192128.Scheme(), + mceliece8192128f.Scheme(), hybrid.Kyber512X25519(), hybrid.Kyber768X25519(), hybrid.Kyber768X448(), diff --git a/kem/schemes/schemes_test.go b/kem/schemes/schemes_test.go index 91fd1fea4..9e1a54d23 100644 --- a/kem/schemes/schemes_test.go +++ b/kem/schemes/schemes_test.go @@ -155,6 +155,16 @@ func Example_schemes() { // Kyber512 // Kyber768 // Kyber1024 + // mceliece348864 + // mceliece348864f + // mceliece460896 + // mceliece460896f + // mceliece6688128 + // mceliece6688128f + // mceliece6960119 + // mceliece6960119f + // mceliece8192128 + // mceliece8192128f // Kyber512-X25519 // Kyber768-X25519 // Kyber768-X448 diff --git a/math/gf2e12/gf4096.go b/math/gf2e12/gf4096.go new file mode 100644 index 000000000..1832eca0e --- /dev/null +++ b/math/gf2e12/gf4096.go @@ -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/math/gf2e12/gf_test.go b/math/gf2e12/gf_test.go new file mode 100644 index 000000000..bef164b7a --- /dev/null +++ b/math/gf2e12/gf_test.go @@ -0,0 +1,88 @@ +package gf2e12 + +import ( + "testing" + + "github.com/cloudflare/circl/internal/test" +) + +type ( + tadd func(x, y Elt) Elt + tmul func(x, y Elt) Elt + tsqr func(x Elt) Elt + tinv func(x Elt) Elt + tdiv func(x, y Elt) Elt +) + +func assertEq(t *testing.T, a, b Elt) { + t.Helper() + if a != b { + test.ReportError(t, a, b) + } +} + +func TestGeneric(t *testing.T) { + t.Run("Add", func(t *testing.T) { testAdd(t, Add) }) + t.Run("Mul", func(t *testing.T) { testMul(t, Mul) }) + t.Run("sqr", func(t *testing.T) { testSqr(t, sqr) }) + t.Run("Inv", func(t *testing.T) { testInv(t, Inv) }) + t.Run("Div", func(t *testing.T) { testDiv(t, Div) }) +} + +func testDiv(t *testing.T, div tdiv) { + assertEq(t, div(0, 2), 0) + assertEq(t, div(4, 2), 2) + assertEq(t, div(9, 3), 7) + assertEq(t, div(10, 550), 3344) +} + +func testInv(t *testing.T, inv tinv) { + assertEq(t, inv(0), 0) + assertEq(t, inv(1), 1) + assertEq(t, inv(2), 2052) + assertEq(t, inv(3), 4088) + assertEq(t, inv(4), 1026) + assertEq(t, inv(4095), 1539) +} + +func testSqr(t *testing.T, sqr tsqr) { + assertEq(t, sqr(0), 0) + assertEq(t, sqr(1), 1) + assertEq(t, sqr(2), 4) + assertEq(t, sqr(3), 5) + assertEq(t, sqr(4), 16) + assertEq(t, sqr(4095), 2746) +} + +func testMul(t *testing.T, mul tmul) { + assertEq(t, mul(0, 0), 0) + assertEq(t, mul(0, 1), 0) + assertEq(t, mul(1, 0), 0) + assertEq(t, mul(0, 5), 0) + assertEq(t, mul(5, 0), 0) + assertEq(t, mul(0, 1024), 0) + assertEq(t, mul(1024, 0), 0) + assertEq(t, mul(2, 6), 12) + assertEq(t, mul(6, 2), 12) + assertEq(t, mul(3, 8), 24) + assertEq(t, mul(8, 3), 24) + assertEq(t, mul(125, 19), 1879) + assertEq(t, mul(19, 125), 1879) + assertEq(t, mul(125, 37), 3625) + assertEq(t, mul(37, 125), 3625) + assertEq(t, mul(4095, 1), 4095) + assertEq(t, mul(1, 4095), 4095) + assertEq(t, mul(550, 3344), 10) + assertEq(t, mul(3344, 550), 10) +} + +func testAdd(t *testing.T, add tadd) { + assertEq(t, add(0x0000, 0x0000), 0x0000) + assertEq(t, add(0x0000, 0x0001), 0x0001) + assertEq(t, add(0x0001, 0x0000), 0x0001) + assertEq(t, add(0x0001, 0x0001), 0x0000) + assertEq(t, add(0x000F, 0x0000), 0x000F) + assertEq(t, add(0x000F, 0x0001), 0x000E) + assertEq(t, add(0x00FF, 0x0100), 0x01FF) + assertEq(t, add(0xF0F0, 0x0F0F), 0xFFFF) +} diff --git a/math/gf2e13/gf8192.go b/math/gf2e13/gf8192.go new file mode 100644 index 000000000..10ddfab8c --- /dev/null +++ b/math/gf2e13/gf8192.go @@ -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/math/gf2e13/gf_test.go b/math/gf2e13/gf_test.go new file mode 100644 index 000000000..16758a0d5 --- /dev/null +++ b/math/gf2e13/gf_test.go @@ -0,0 +1,144 @@ +package gf2e13 + +import ( + "testing" + + "github.com/cloudflare/circl/internal/test" +) + +type ( + tadd func(x, y Elt) Elt + tmul func(x, y Elt) Elt + tsqr2 func(x Elt) Elt + tsqrmul func(x, y Elt) Elt + tsqr2mul func(x, y Elt) Elt + tinv func(x Elt) Elt + tdiv func(x, y Elt) Elt +) + +func assertEq(t *testing.T, a, b Elt) { + t.Helper() + if a != b { + test.ReportError(t, b, a) + } +} + +func TestGeneric(t *testing.T) { + t.Run("Add", func(t *testing.T) { testAdd(t, Add) }) + t.Run("Mul", func(t *testing.T) { testMul(t, Mul) }) + t.Run("sqr2", func(t *testing.T) { testSqr2(t, sqr2) }) + t.Run("sqrMul", func(t *testing.T) { testSqrMul(t, sqrMul) }) + t.Run("sqr2Mul", func(t *testing.T) { testSqr2Mul(t, sqr2Mul) }) + t.Run("Inv", func(t *testing.T) { testInv(t, Inv) }) + t.Run("Div", func(t *testing.T) { testDiv(t, Div) }) +} + +func testSqr2Mul(t *testing.T, sqr2Mul tsqr2mul) { + assertEq(t, sqr2Mul(0, 0), 0) + assertEq(t, sqr2Mul(0, 1), 0) + assertEq(t, sqr2Mul(1, 0), 0) + assertEq(t, sqr2Mul(0, 5), 0) + assertEq(t, sqr2Mul(5, 0), 0) + assertEq(t, sqr2Mul(0, 1024), 0) + assertEq(t, sqr2Mul(1024, 0), 0) + assertEq(t, sqr2Mul(2, 6), 96) + assertEq(t, sqr2Mul(6, 2), 544) + assertEq(t, sqr2Mul(3, 8), 136) + assertEq(t, sqr2Mul(8, 3), 4123) + assertEq(t, sqr2Mul(125, 19), 3075) + assertEq(t, sqr2Mul(19, 125), 590) + assertEq(t, sqr2Mul(125, 37), 5123) + assertEq(t, sqr2Mul(37, 125), 854) + assertEq(t, sqr2Mul(4095, 1), 2883) + assertEq(t, sqr2Mul(1, 4095), 4095) + assertEq(t, sqr2Mul(8191, 1), 5190) + assertEq(t, sqr2Mul(1, 8191), 8191) +} + +func testSqrMul(t *testing.T, sqrMul tsqrmul) { + assertEq(t, sqrMul(0, 0), 0) + assertEq(t, sqrMul(0, 1), 0) + assertEq(t, sqrMul(1, 0), 0) + assertEq(t, sqrMul(0, 5), 0) + assertEq(t, sqrMul(5, 0), 0) + assertEq(t, sqrMul(0, 1024), 0) + assertEq(t, sqrMul(1024, 0), 0) + assertEq(t, sqrMul(2, 6), 24) + assertEq(t, sqrMul(6, 2), 40) + assertEq(t, sqrMul(3, 8), 40) + assertEq(t, sqrMul(8, 3), 192) + assertEq(t, sqrMul(125, 19), 2582) + assertEq(t, sqrMul(19, 125), 7332) + assertEq(t, sqrMul(125, 37), 3012) + assertEq(t, sqrMul(37, 125), 4916) + assertEq(t, sqrMul(4095, 1), 3392) + assertEq(t, sqrMul(1, 4095), 4095) + assertEq(t, sqrMul(8191, 1), 5402) + assertEq(t, sqrMul(1, 8191), 8191) +} + +func testDiv(t *testing.T, div tdiv) { + assertEq(t, div(6733, 1), 6733) + assertEq(t, div(0, 2), 0) + assertEq(t, div(4, 2), 2) + assertEq(t, div(4096, 2), 2048) + assertEq(t, div(9, 3), 7) + assertEq(t, div(4591, 5), 4205) + assertEq(t, div(10, 550), 7759) + assertEq(t, div(3, 5501), 1770) +} + +func testInv(t *testing.T, inv tinv) { + assertEq(t, inv(0), 0) + assertEq(t, inv(1), 1) + assertEq(t, inv(2), 4109) + assertEq(t, inv(3), 8182) + assertEq(t, inv(4), 6155) + assertEq(t, inv(4095), 4657) + assertEq(t, inv(4096), 911) + assertEq(t, inv(8191), 5953) +} + +func testSqr2(t *testing.T, sqr2 tsqr2) { + assertEq(t, sqr2(0), 0) + assertEq(t, sqr2(1), 1) + assertEq(t, sqr2(2), 16) + assertEq(t, sqr2(3), 17) + assertEq(t, sqr2(4), 256) + assertEq(t, sqr2(4095), 2883) + assertEq(t, sqr2(4096), 7941) + assertEq(t, sqr2(8191), 5190) +} + +func testMul(t *testing.T, mul tmul) { + assertEq(t, mul(0, 0), 0) + assertEq(t, mul(0, 1), 0) + assertEq(t, mul(1, 0), 0) + assertEq(t, mul(0, 5), 0) + assertEq(t, mul(5, 0), 0) + assertEq(t, mul(0, 1024), 0) + assertEq(t, mul(1024, 0), 0) + assertEq(t, mul(2, 6), 12) + assertEq(t, mul(6, 2), 12) + assertEq(t, mul(3, 8), 24) + assertEq(t, mul(8, 3), 24) + assertEq(t, mul(125, 19), 1879) + assertEq(t, mul(19, 125), 1879) + assertEq(t, mul(125, 37), 3625) + assertEq(t, mul(37, 125), 3625) + assertEq(t, mul(4095, 1), 4095) + assertEq(t, mul(1, 4095), 4095) + assertEq(t, mul(8191, 1), 8191) + assertEq(t, mul(1, 8191), 8191) +} + +func testAdd(t *testing.T, add tadd) { + assertEq(t, add(0x0000, 0x0000), 0x0000) + assertEq(t, add(0x0000, 0x0001), 0x0001) + assertEq(t, add(0x0001, 0x0000), 0x0001) + assertEq(t, add(0x0001, 0x0001), 0x0000) + assertEq(t, add(0x000F, 0x0000), 0x000F) + assertEq(t, add(0x000F, 0x0001), 0x000E) + assertEq(t, add(0x00FF, 0x0100), 0x01FF) + assertEq(t, add(0xF0F0, 0x0F0F), 0xFFFF) +}