Squashed 'src/minisketch/' changes from ea8f66b1ea..d1bd01e189
What changed, and why it matters
This commit is a routine subtree update that pulls in the latest minisketch library changes. The visible changes are almost entirely build-system and documentation additions: a new CMake build system, CI configuration files, README updates, and generated field-parameter documentation. There is no indication in the commit message or diff of any bug fix, behavior change, or security patch to the actual sketching code.
No security action required. Treat as a normal dependency/build-system update. If desired, verify the full upstream minisketch changelog between ea8f66b1ea and d1bd01e189 for any non-build changes not captured in this squash summary.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit is a git subtree squash merge of bitcoin-core/minisketch from ea8f66b1ea to d1bd01e189. The included upstream commits are: a trailing-whitespace cleanup, introduction of a CMake-based build system, a GitHub Actions CI workflow for native Windows builds, and README documentation for CMake. The diff shows only additions of build/CI/docs files; no modifications to the core minisketch C++ implementation or public API are present in the supplied diff excerpt.
Changed components
src/minisketch build systemsrc/minisketch CI configurationsrc/minisketch documentationInspect captured patch +9129 / −0
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 00000000..5ceefee2
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,157 @@
+env:
+ BUILD: check
+ HOST:
+ MAKEFLAGS: -j4
+ BENCH: yes
+ TESTRUNS:
+ EXEC_CMD:
+ ENABLE_FIELDS:
+
+cat_logs_snippet: &CAT_LOGS
+ on_failure:
+ cat_test_log_script:
+ - cat test-suite.log || true
+ cat_config_log_script:
+ - cat config.log || true
+ cat_test_env_script:
+ - cat test_env.log || true
+ cat_ci_env_script:
+ - env
+
+merge_base_script_snippet: &MERGE_BASE
+ merge_base_script:
+ - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
+ - git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH
+ - git config --global user.email "ci@ci.ci"
+ - git config --global user.name "ci"
+ - git merge FETCH_HEAD # Merge base to detect silent merge conflicts
+
+env_matrix_snippet: &ENV_MATRIX_VALGRIND
+ - env:
+ ENABLE_FIELDS: "7,32,58"
+ - env:
+ BUILD: distcheck
+ - env:
+ EXEC_CMD: valgrind --error-exitcode=42
+ TESTRUNS: 1
+ BUILD:
+
+env_matrix_snippet: &ENV_MATRIX_SAN_VALGRIND
+ - env:
+ ENABLE_FIELDS: "11,64,37"
+ - env:
+ BUILD: distcheck
+ - env:
+ EXEC_CMD: valgrind --error-exitcode=42
+ TESTRUNS: 1
+ BUILD:
+ - env:
+ CXXFLAGS: "-fsanitize=undefined -fno-omit-frame-pointer"
+ LDFLAGS: "-fsanitize=undefined -fno-omit-frame-pointer"
+ UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"
+ BENCH: no
+
+task:
+ name: "x86_64: Linux (Debian stable)"
+ container:
+ dockerfile: ci/linux-debian.Dockerfile
+ memory: 2G
+ cpu: 4
+ matrix:
+ << : *ENV_MATRIX_SAN_VALGRIND
+ matrix:
+ - env:
+ CXX: g++
+ - env:
+ CXX: clang++ -gdwarf-4
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ name: "i686: Linux (Debian stable)"
+ container:
+ dockerfile: ci/linux-debian.Dockerfile
+ memory: 2G
+ cpu: 4
+ env:
+ HOST: i686-linux-gnu
+ matrix:
+ << : *ENV_MATRIX_VALGRIND
+ matrix:
+ - env:
+ CXX: i686-linux-gnu-g++
+ - env:
+ CXX: clang++ --target=i686-linux-gnu -gdwarf-4
+ CXXFLAGS: -g -O2 -isystem /usr/i686-linux-gnu/include -isystem /usr/i686-linux-gnu/include/c++/10/i686-linux-gnu
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ name: "arm64: macOS Monterey"
+ macos_instance:
+ image: ghcr.io/cirruslabs/macos-monterey-base:latest
+ env:
+ # Cirrus gives us a fixed number of 4 virtual CPUs.
+ MAKEFLAGS: -j5
+ matrix:
+ - env:
+ CXX: g++-11
+ # Homebrew's gcc for arm64 has no libubsan.
+ matrix:
+ - env:
+ ENABLE_FIELDS: 28
+ - env:
+ BUILD: distcheck
+ - env:
+ CXX: clang++
+ matrix:
+ - env:
+ ENABLE_FIELDS: 28
+ - env:
+ BUILD: distcheck
+ - env:
+ CXXFLAGS: "-fsanitize=undefined -fno-omit-frame-pointer"
+ LDFLAGS: "-fsanitize=undefined -fno-omit-frame-pointer"
+ UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"
+ BENCH: no
+ brew_script:
+ - brew update
+ - brew install automake libtool gcc@11
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ name: "s390x (big-endian): Linux (Debian stable, QEMU)"
+ container:
+ dockerfile: ci/linux-debian.Dockerfile
+ cpu: 4
+ memory: 2G
+ env:
+ EXEC_CMD: qemu-s390x
+ HOST: s390x-linux-gnu
+ BUILD:
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
+
+task:
+ name: "x86_64-w64-mingw32: Linux (Debian stable, Wine)"
+ container:
+ dockerfile: ci/linux-debian.Dockerfile
+ cpu: 4
+ memory: 2G
+ env:
+ EXEC_CMD: wine
+ EXEC_EXT: .exe
+ HOST: x86_64-w64-mingw32
+ BUILD:
+ << : *MERGE_BASE
+ test_script:
+ - ./ci/cirrus.sh
+ << : *CAT_LOGS
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..8a57838b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,69 @@
+name: CI
+on:
+ pull_request:
+ push:
+ branches:
+ - '**'
+ tags-ignore:
+ - '**'
+
+concurrency:
+ group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ windows-native:
+ name: ${{ matrix.configuration.job_name }}
+ # See: https://github.com/actions/runner-images#available-images.
+ runs-on: windows-2025
+
+ strategy:
+ fail-fast: false
+ matrix:
+ configuration:
+ - job_name: 'x64 (MSVC): Windows (VS 2022)'
+ build_configuration: 'Release'
+ - job_name: 'x64 (MSVC): Windows (VS 2022, fields=32)'
+ cmake_options: '-DMINISKETCH_FIELDS=32'
+ build_configuration: 'Release'
+ - job_name: 'x64 (MSVC): Windows (VS 2022, debug)'
+ build_configuration: 'Debug'
+ # TODO: Resolve the issue and re-enable benchmark.
+ # See: https://github.com/bitcoin-core/minisketch/pull/96.
+ skip_benchmark: true
+ - job_name: 'x64 (MSVC): Windows (VS 2022, shared)'
+ cmake_options: '-DBUILD_SHARED_LIBS=ON'
+ build_configuration: 'Release'
+ - job_name: 'x64 (clang-cl): Windows (VS 2022)'
+ cmake_options: '-T ClangCL'
+ build_configuration: 'Release'
+ # TODO: Resolve the issue and re-enable benchmark.
+ # See: https://github.com/bitcoin-core/minisketch/pull/96.
+ skip_benchmark: true
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Generate buildsystem
+ env:
+ CXXFLAGS: '/WX'
+ run: cmake -B build -DMINISKETCH_BUILD_BENCHMARK=ON ${{ matrix.configuration.cmake_options }}
+
+ - name: Build
+ run: cmake --build build --config ${{ matrix.configuration.build_configuration }}
+
+ - name: Binaries info
+ shell: bash
+ run: |
+ cd build/bin/${{ matrix.configuration.build_configuration }}
+ file * | grep "\.exe\|\.dll"
+
+ - name: Check
+ working-directory: build
+ run: ctest --output-on-failure -j $env:NUMBER_OF_PROCESSORS -C ${{ matrix.configuration.build_configuration }}
+
+ - name: Benchmark
+ if: ${{ ! matrix.configuration.skip_benchmark }}
+ working-directory: build
+ run: bin\${{ matrix.configuration.build_configuration }}\bench.exe
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..fab0b2eb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+*.o
+*.lo
+*.la
+*.dll
+*.dylib
+*.so.*
+.*
+*.a
+*~
+
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache/
+build-aux/config.guess
+build-aux/config.sub
+build-aux/depcomp
+build-aux/install-sh
+build-aux/ltmain.sh
+build-aux/m4/libtool.m4
+build-aux/m4/lt~obsolete.m4
+build-aux/m4/ltoptions.m4
+build-aux/m4/ltsugar.m4
+build-aux/m4/ltversion.m4
+build-aux/missing
+build-aux/compile
+build-aux/test-driver
+config.log
+config.status
+configure
+libtool
+stamp-h1
+
+test*
+bench
+
+# CMake build directories.
+/*build*
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..f760ac09
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,122 @@
+cmake_minimum_required(VERSION 3.22)
+
+#=============================
+# Project / Package Metadata
+#=============================
+project(minisketch
+ VERSION 0.0.1
+ DESCRIPTION "A library for BCH-based set reconciliation"
+ HOMEPAGE_URL "https://github.com/bitcoin-core/minisketch"
+ LANGUAGES CXX
+)
+
+# ============================================================
+# Project Initialization
+# ============================================================
+enable_testing()
+include(CTestUseLaunchers)
+
+list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+
+if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
+endif()
+if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+endif()
+if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
+ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
+endif()
+
+# Prevent include directories from parent project from leaking into this one.
+set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "")
+
+#=============================
+# Language Setup
+#=============================
+if(DEFINED CMAKE_CXX_STANDARD)
+ if(CMAKE_CXX_STANDARD EQUAL 98 OR CMAKE_CXX_STANDARD LESS 11)
+ message(FATAL_ERROR "This project requires at least C++11")
+ endif()
+else()
+ set(CMAKE_CXX_STANDARD 11)
+endif()
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+if(NOT DEFINED CMAKE_CXX_EXTENSIONS)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+endif()
+
+#=============================
+# Configurable Options
+#=============================
+option(MINISKETCH_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
+if(NOT PROJECT_IS_TOP_LEVEL)
+ mark_as_advanced(MINISKETCH_INSTALL)
+endif()
+
+option(MINISKETCH_BUILD_TESTS "Build tests." ON)
+option(MINISKETCH_BUILD_BENCHMARK "Build benchmark." OFF)
+
+set(supported_fields "")
+set(have_enabled_fields NO)
+set(have_disabled_fields NO)
+foreach(i RANGE 2 64)
+ list(APPEND supported_fields ${i})
+endforeach()
+if(NOT DEFINED MINISKETCH_FIELDS)
+ set(MINISKETCH_FIELDS ${supported_fields} CACHE STRING "Semicolon-separated list of field sizes to build. Default=all. Available sizes: ${supported_fields}.")
+endif()
+foreach(field IN LISTS supported_fields)
+ if(field IN_LIST MINISKETCH_FIELDS)
+ set(have_enabled_fields YES)
+ else()
+ set(have_disabled_fields YES)
+ add_compile_definitions(DISABLE_FIELD_${field})
+ endif()
+endforeach()
+if(NOT have_enabled_fields)
+ message(FATAL_ERROR "No field sizes are enabled.")
+endif()
+unset(have_enabled_fields)
+unset(supported_fields)
+
+#=============================
+# Build Options
+#=============================
+set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+
+if(MSVC)
+ add_compile_options(/Zc:__cplusplus)
+endif()
+
+if(MINGW)
+ add_link_options(-static)
+endif()
+
+#=============================
+# Diagnostics Options
+#=============================
+if(MSVC)
+ # For both MSVC's cl.exe and clang-cl compilers.
+ add_compile_options(/W3) # Production quality warning level. Enables -Wall Clang's core option.
+else()
+ add_compile_options(-Wall)
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ add_compile_options(/wd4060) # Disable warning C4060 "switch statement contains no 'case' or 'default' labels".
+ add_compile_options(/wd4065) # Disable warning C4065 "switch statement contains 'default' but no 'case' labels".
+ add_compile_options(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
+ add_compile_options(/wd4244) # Disable warning C4244 "conversion from 'type1' to 'type2', possible loss of data".
+else()
+ add_compile_options(-Wundef)
+endif()
+
+#=============================
+# Main Processing
+#=============================
+include(SystemIntrospection)
+add_subdirectory(src)
+
+include(PrintConfigureSummary)
+print_configure_summary()
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..b25e3cae
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..86a5c9dc
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,92 @@
+ACLOCAL_AMFLAGS = -I build-aux/m4
+AM_CXXFLAGS = $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS)
+
+include sources.mk
+
+include_HEADERS = $(MINISKETCH_DIST_HEADERS_INT)
+noinst_HEADERS = $(MINISKETCH_LIB_HEADERS_INT) $(MINISKETCH_FIELD_GENERIC_HEADERS_INT) $(MINISKETCH_FIELD_CLMUL_HEADERS_INT)
+
+LIBMINISKETCH = libminisketch.la
+LIBMINISKETCH_FIELD_GENERIC = libminisketch_field_generic.la
+if ENABLE_CLMUL
+LIBMINISKETCH_FIELD_CLMUL = libminisketch_field_clmul.la
+endif
+if USE_TESTS
+LIBMINISKETCH_VERIFY=libminisketch_verify.la
+LIBMINISKETCH_FIELD_GENERIC_VERIFY=libminisketch_field_generic_verify.la
+if ENABLE_CLMUL
+LIBMINISKETCH_FIELD_CLMUL_VERIFY=libminisketch_field_clmul_verify.la
+endif
+endif
+
+lib_LTLIBRARIES =
+lib_LTLIBRARIES += $(LIBMINISKETCH)
+
+noinst_LTLIBRARIES =
+noinst_LTLIBRARIES += $(LIBMINISKETCH_FIELD_GENERIC)
+noinst_LTLIBRARIES += $(LIBMINISKETCH_FIELD_GENERIC_VERIFY)
+noinst_LTLIBRARIES += $(LIBMINISKETCH_FIELD_CLMUL)
+noinst_LTLIBRARIES += $(LIBMINISKETCH_FIELD_CLMUL_VERIFY)
+noinst_LTLIBRARIES += $(LIBMINISKETCH_VERIFY)
+
+# Release libs
+libminisketch_field_generic_la_SOURCES = $(MINISKETCH_FIELD_GENERIC_SOURCES_INT)
+libminisketch_field_generic_la_CPPFLAGS = $(AM_CPPFLAGS) $(RELEASE_DEFINES)
+
+libminisketch_field_clmul_la_SOURCES = $(MINISKETCH_FIELD_CLMUL_SOURCES_INT)
+libminisketch_field_clmul_la_CPPFLAGS = $(AM_CPPFLAGS) $(RELEASE_DEFINES)
+libminisketch_field_clmul_la_CXXFLAGS = $(AM_CXXFLAGS) $(CLMUL_CXXFLAGS)
+
+libminisketch_la_SOURCES = $(MINISKETCH_LIB_SOURCES_INT)
+libminisketch_la_CPPFLAGS = $(AM_CPPFLAGS) $(RELEASE_DEFINES)
+libminisketch_la_LIBADD = $(LIBMINISKETCH_FIELD_CLMUL) $(LIBMINISKETCH_FIELD_GENERIC)
+
+# Libs with extra verification checks
+libminisketch_field_generic_verify_la_SOURCES = $(MINISKETCH_FIELD_GENERIC_SOURCES_INT)
+libminisketch_field_generic_verify_la_CPPFLAGS = $(AM_CPPFLAGS) $(VERIFY_DEFINES)
+
+libminisketch_field_clmul_verify_la_SOURCES = $(MINISKETCH_FIELD_CLMUL_SOURCES_INT)
+libminisketch_field_clmul_verify_la_CPPFLAGS = $(AM_CPPFLAGS) $(VERIFY_DEFINES)
+libminisketch_field_clmul_verify_la_CXXFLAGS = $(AM_CXXFLAGS) $(CLMUL_CXXFLAGS)
+
+libminisketch_verify_la_SOURCES = $(MINISKETCH_LIB_SOURCES_INT)
+libminisketch_verify_la_CPPFLAGS = $(AM_CPPFLAGS) $(VERIFY_DEFINES)
+libminisketch_verify_la_LIBADD = $(LIBMINISKETCH_FIELD_CLMUL_VERIFY) $(LIBMINISKETCH_FIELD_GENERIC_VERIFY)
+
+noinst_PROGRAMS =
+if USE_BENCHMARK
+noinst_PROGRAMS += bench
+endif
+if USE_TESTS
+noinst_PROGRAMS += test test-verify
+TESTS = test test-verify
+endif
+
+bench_SOURCES = $(MINISKETCH_BENCH_SOURCES_INT)
+bench_CPPFLAGS = $(AM_CPPFLAGS) $(RELEASE_DEFINES)
+bench_LDADD = $(LIBMINISKETCH)
+bench_LDFLAGS = $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+
+test_SOURCES = $(MINISKETCH_TEST_SOURCES_INT)
+test_CPPFLAGS = $(AM_CPPFLAGS) $(RELEASE_DEFINES)
+test_LDADD = $(LIBMINISKETCH)
+test_LDFLAGS = $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+
+test_verify_SOURCES = $(MINISKETCH_TEST_SOURCES_INT)
+test_verify_CPPFLAGS = $(AM_CPPFLAGS) $(VERIFY_DEFINES)
+test_verify_LDADD = $(LIBMINISKETCH_VERIFY)
+test_verify_LDFLAGS = $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+
+EXTRA_DIST=
+EXTRA_DIST += LICENSE
+EXTRA_DIST += README.md
+EXTRA_DIST += doc/example.c
+EXTRA_DIST += doc/gen_params.sage
+EXTRA_DIST += doc/math.md
+EXTRA_DIST += doc/moduli.md
+EXTRA_DIST += doc/plot_bits.png
+EXTRA_DIST += doc/plot_capacity.png
+EXTRA_DIST += doc/plot_diff.png
+EXTRA_DIST += doc/plot_size.png
+EXTRA_DIST += doc/protocoltips.md
+EXTRA_DIST += tests/pyminisketch.py
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..a4ffeac9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,248 @@
+# Minisketch: a library for [BCH](https://en.wikipedia.org/wiki/BCH_code)-based set reconciliation
+<img align="right" src="doc/minisketch-vs.png" />
+
+`libminisketch` is an optimized standalone MIT-licensed library with C API for constructing and decoding *set sketches*, which can be used for compact set reconciliation and other applications.
+It is an implementation of the PinSketch<sup>[[1]](#myfootnote1)</sup> algorithm. An explanation of the algorithm can be found [here](doc/math.md).
+
+## Sketches for set reconciliation
+
+Sketches, as produced by this library, can be seen as "set checksums" with two peculiar properties:
+* Sketches have a predetermined capacity, and when the number of elements in the set is not higher than the capacity, `libminisketch` will always recover the entire set from the sketch. A sketch of *b*-bit elements with capacity *c* can be stored in *bc* bits.
+* The sketches of two sets can be combined by adding them (XOR) to obtain a sketch of the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) between the two sets (*i.e.*, all elements that occur in one but not both input sets).
+
+This makes them appropriate for a very bandwidth-efficient set reconciliation protocol. If Alice and Bob each have a set of elements, and they suspect that the sets largely but not entirely overlap,
+they can use the following protocol to let both parties learn all the elements:
+* Alice and Bob both compute a sketch of their set elements.
+* Alice sends her sketch to Bob.
+* Bob combines the two sketches, and obtains a sketch of the symmetric difference.
+* Bob tries to recover the elements from the difference sketch.
+* Bob sends every element in the difference that he has to Alice.
+
+This will always succeed when the size of the difference (elements that Alice has but Bob doesn't plus elements that Bob has but Alice doesn't) does not exceed the
+capacity of the sketch that Alice sent. The interesting part is that this works regardless of the actual set sizes—only the difference matters.
+
+If the elements are large, it may be preferable to compute the sketches over *hashes* of the set elements. In that case an additional step is added to the protocol, where Bob also sends the hash
+of every element he does not have to Alice, who responds with the requested elements.
+
+The doc/ directory has additional [tips for designing reconciliation protocols using libminisketch](doc/protocoltips.md).
+
+## Evaluation
+
+<img src="doc/plot_capacity.png" width="432" height="324" /> <img src="doc/plot_diff.png" width="432" height="324" />
+
+<img src="doc/plot_size.png" width="432" height="324" /> <img src="doc/plot_bits.png" width="432" height="324" />
+
+**The first graph** above shows a benchmark of `libminisketch` against three other set reconciliation algorithms/implementations. The benchmarks were performed using a single core on a system with an Intel Core i7-7820HQ CPU with clock speed locked at 2.4 GHz. The diagram shows the time needed for merging of two sketches and decoding the result. The creation of a sketch on the same machine takes around 5 ns per capacity and per set element. The other implementations are:
+* [`pinsketch`](https://www.cs.bu.edu/~reyzin/code/fuzzy.html), the original PinSketch implementation.
+* [`cpisync`](https://github.com/trachten/cpisync), a software project which implements a number of set reconciliation algorithms and protocols. The included benchmark analyzes the non-probabilistic version of the original CPISync algorithm<sup>[[5]](#myfootnote5)</sup> only.
+* A high-performance custom IBLT implementation using 4 hash functions and 32-bit checksums.
+
+For the largest sizes currently of interest to the authors, such as a set of capacity 4096 with 1024 differences, `libminisketch` is forty-nine times faster than `pinsketch` and over eight thousand times faster than `cpisync`. `libminisketch` is fast enough on realistic set sizes for use on high-traffic network servers where computational resources are limited.
+
+Even where performance is latency-limited, small minisketches can be fast enough to improve performance. On the above i7-7820HQ, a set of 2500 30-bit entries with a difference of 20 elements can be communicated in less time with a minisketch than sending the raw set so long as the communications bandwidth is 1 gigabit per second or less; an eight-element difference can be communicated in better than one-fifth the time on a gigabit link.
+
+**The second graph** above shows the performance of the same algorithms on the same system, but this time keeping the capacity constant at 128, while varying the number of differences to reconcile between 1 and 128. It shows how `cpisync`'s reconciliation speed is mostly dependent on capacity, while `pinsketch`/`libminisketch` are more dependent on number of differences.
+
+**The third graph** above shows the size overhead of a typical IBLT scheme over the other algorithms (which are near-optimal bandwidth), for various levels of failure probability. IBLT takes tens of times the bandwidth of `libminisketch` sketches when the set difference size is small and the required failure rate is low.
+
+**The fourth graph** above shows the effect of the field size on speed in `libminisketch`. The three lines correspond to:
+* CLMUL 64-bit: Intel Core i7-7820HQ system at 2.4 GHz
+* Generic 64-bit: POWER9 CP9M06 system at 2.8 GHz (Talos II)
+* Generic 32-bit: Cortex-A53 at 1.2 GHz (Raspberry Pi 3B)
+
+It shows how CLMUL implementations are faster for certain fields (specifically, field sizes for which an irreducible polynomial of the form *x<sup>b</sup> + x + 1* over *GF(2)* exists, and to a lesser extent, fields which are a multiple of 8 bits). It also shows how (for now) a significant performance drop exists for fields larger than 32 bits on 32-bit platforms. Note that the three lines are not at the same scale (the Raspberry Pi 3B is around 10x slower for 32-bit fields than the Core i7; the POWER9 is around 1.3x slower).
+
+Below we compare the PinSketch algorithm (which `libminisketch` is an implementation of) with other set reconciliation algorithms:
+
+| Algorithm | Sketch size | Decode success | Decoding complexity | Difference type | Secure sketch |
+| ----------------------------------------------------- | ------------------------- | ---------------| ------------------- | --------------- | ------------- |
+| CPISync<sup>[[2]](#myfootnote2)</sup> | *(b+1)c* | Always | *O(n<sup>3</sup>)* | Both | Yes |
+| PinSketch<sup>[[1]](#myfootnote1)</sup> | *bc* | Always | *O(n<sup>2</sup>)* | Symmetric only | Yes |
+| IBLT<sup>[[6]](#myfootnote1)[[7]](#myfootnote1)</sup> | *αbc* (see graph 3) | Probabilistic | *O(n)* | Depends | No |
+
+* **Sketch size:** This column shows the size in bits of a sketch designed for reconciling *c* different *b*-bit elements. PinSketch and CPISync have a near-optimal<sup>[[11]](#myfootnote11)</sup> communication overhead, which in practice means the sketch size is very close (or equal to) *bc* bits. That is the same size as would be needed to transfer the elements of the difference naively (which is remarkable, as the difference isn't even known by the sender). For IBLT there is an overhead factor *α*, which depends on various design parameters, but is often between *2* and *10*.
+* **Decode success:** Whenever a sketch is designed with a capacity not lower than the actual difference size, CPISync and PinSketch guarantee that decoding of the difference will always succeed. IBLT always has a chance of failure, though that chance can be made arbitrarily small by increasing the communication overhead.
+* **Decoding complexity:** The space savings achieved by near-optimal algorithms come at a cost in performance, as their asymptotic decode complexity is quadratic or cubic, while IBLT is linear. This means that using near-optimal algorithms can be too expensive for applications where the difference is sufficiently large.
+* **Difference type:** PinSketch can only compute the symmetric difference from a merged sketch, while CPISync and IBLT can distinguish which side certain elements were missing on. When the decoder has access to one of the sets, this generally doesn't matter, as he can look up each of the elements in the symmetric difference with one of the sets.
+* **Secure sketch:** Whether the sketch satisfies the definition of a secure sketch<sup>[[1]](#myfootnote1)</sup>, which implies a minimal amount about a set can be extracted from a sketch by anyone who does not know most of the elements already. This makes the algorithm appropriate for applications like fingerprint authentication.
+
+## Building with Autotools
+
+The build system is very rudimentary for now, and [improvements](https://github.com/bitcoin-core/minisketch/pulls) are welcome.
+
+The following may work and produce a `libminisketch.a` file you can link against:
+
+```bash
+git clone https://github.com/bitcoin-core/minisketch
+cd minisketch
+./autogen.sh && ./configure && make
+```
+
+## Building with CMake
+
+To maintain a pristine source tree, CMake encourages performing an out-of-source build by using a separate dedicated build directory.
+
+### Building on POSIX systems
+
+The following commands will produce the same `libminisketch.a` file as in the example [above](#building-with-autotools):
+
+```bash
+cmake -B build -DCMAKE_CXX_FLAGS="-g -O2" # Generate a build system in subdirectory "build"
+cmake --build build # Run the actual build process
+ctest --test-dir build # Run the test suite
+sudo cmake --install build # Install the library into the system (optional)
+```
+
+Run `cmake -B build -LH` or `ccmake -B build` to see the full list of configurable build options.
+
+### Cross compiling
+
+The following example works on modern Ubuntu/Debian systems:
+
+```bash
+sudo apt install g++-mingw-w64-x86-64-posix
+cmake -B build -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++-posix
+cmake --build build
+```
+
+### Building on Windows
+
+The following example assumes the use of Visual Studio 2022 and CMake v3.21 or newer.
+
+In "Developer Command Prompt for VS 2022":
+
+```cmd
+cmake -B build
+cmake --build build --config Release
+```
+
+## Usage
+
+In this section Alice and Bob are trying to find the difference between their sets.
+Alice has the set *[3000 ... 3009]*, while Bob has *[3002 ... 3011]*.
+
+First, Alice creates a sketch:
+
+```c
+#include <stdio.h>
+#include <assert.h>
+#include "../include/minisketch.h"
+int main(void) {
+
+ minisketch *sketch_a = minisketch_create(12, 0, 4);
+```
+
+The arguments are:
+* The field size *b*, which specifies the size of the elements being reconciled. With a field size *b*, the supported range of set elements is the integers from *1* to *2<sup>b</sub>* *- 1*, inclusive. Note that elements cannot be zero.
+* The implementation number. Implementation *0* is always supported, but more efficient algorithms may be available on some hardware. The serialized form of a sketch is independent of the implementation, so different implementations can interoperate.
+* The capacity *c*, which specifies how many differences the resulting sketch can reconcile.
+
+Then Alice adds her elements to her sketch. Note that adding the same element a second time removes it again, as sketches have set semantics, not multiset semantics.
+
+```c
+ for (int i = 3000; i < 3010; ++i) {
+ minisketch_add_uint64(sketch_a, i);
+ }
+```
+
+The next step is serializing the sketch into a byte array:
+
+```c
+ size_t sersize = minisketch_serialized_size(sketch_a);
+ assert(sersize == 12 * 4 / 8); // 4 12-bit values is 6 bytes.
+ unsigned char *buffer_a = malloc(sersize);
+ minisketch_serialize(sketch_a, buffer_a);
+ minisketch_destroy(sketch_a);
+```
+
+The contents of the buffer can then be submitted to Bob, who can create his own sketch:
+
+```c
+ minisketch *sketch_b = minisketch_create(12, 0, 4); // Bob's own sketch
+ for (int i = 3002; i < 3012; ++i) {
+ minisketch_add_uint64(sketch_b, i);
+ }
+```
+
+After Bob receives Alice's serialized sketch, he can reconcile:
+
+```c
+ sketch_a = minisketch_create(12, 0, 4); // Alice's sketch
+ minisketch_deserialize(sketch_a, buffer_a); // Load Alice's sketch
+ free(buffer_a);
+
+ // Merge the elements from sketch_a into sketch_b. The result is a sketch_b
+ // which contains all elements that occurred in Alice's or Bob's sets, but not
+ // in both.
+ minisketch_merge(sketch_b, sketch_a);
+
+ uint64_t differences[4];
+ ssize_t num_differences = minisketch_decode(sketch_b, 4, differences);
+ minisketch_destroy(sketch_a);
+ minisketch_destroy(sketch_b);
+ if (num_differences < 0) {
+ printf("More than 4 differences!\n");
+ } else {
+ ssize_t i;
+ for (i = 0; i < num_differences; ++i) {
+ printf("%u is in only one of the two sets\n", (unsigned)differences[i]);
+ }
+ }
+}
+```
+
+In this example Bob would see output such as:
+
+```
+$ gcc -std=c99 -Wall -Wextra -o example ./doc/example.c -Lsrc/ -lminisketch -lstdc++ && ./example
+3000 is in only one of the two sets
+3011 is in only one of the two sets
+3001 is in only one of the two sets
+3010 is in only one of the two sets
+```
+
+The order of the output is arbitrary and will differ on different runs of minisketch_decode().
+
+## Applications
+
+Communications efficient set reconciliation has been proposed to optimize Bitcoin transaction distribution<sup>[[8]](#myfootnote8)</sup>, which would allow Bitcoin nodes to have many more peers while reducing bandwidth usage. It could also be used for Bitcoin block distribution<sup>[[9]](#myfootnote9)</sup>, particularly for very low bandwidth links such as satellite. A similar approach (CPISync) is used by PGP SKS keyservers to synchronize their databases efficiently. Secure sketches can also be used as helper data to reliably extract a consistent cryptographic key from fuzzy biometric data while leaking minimal information<sup>[[1]](#myfootnote1)</sup>. They can be combined with [dcnets](https://en.wikipedia.org/wiki/Dining_cryptographers_problem) to create cryptographic multiparty anonymous communication<sup>[[10]](#myfootnote10)</sup>.
+
+## Implementation notes
+
+`libminisketch` is written in C++11, but has a [C API](include/minisketch.h) for compatibility reasons.
+
+Specific algorithms and optimizations used:
+* Finite field implementations:
+ * A generic implementation using C unsigned integer bit operations, and one using the [CLMUL instruction](https://en.wikipedia.org/wiki/CLMUL_instruction_set) where available. The latter has specializations for different classes of fields that permit optimizations (those with trinomial irreducible polynomials, and those whose size is a multiple of 8 bits).
+ * Precomputed tables for (repeated) squaring, and for solving equations of the form *x<sup>2</sup> + x = a*<sup>[[2]](#myfootnote2)</sup>.
+ * Inverses are computed using an [exponentiation ladder](https://en.wikipedia.org/w/index.php?title=Exponentiation_by_squaring&oldid=868883860)<sup>[[12]](#myfootnote12)</sup> on systems where multiplications are relatively fast, and using an [extended GCD algorithm](https://en.wikipedia.org/w/index.php?title=Extended_Euclidean_algorithm&oldid=865802511#Computing_multiplicative_inverses_in_modular_structures) otherwise.
+ * Repeated multiplications are accelerated using runtime precomputations on systems where multiplications are relatively slow.
+ * The serialization of field elements always represents them as bits that are coefficients of the lowest-weight (using lexicographic order as tie breaker) irreducible polynomials over *GF(2)* (see [this list](doc/moduli.md)), but for some implementations they are converted to a different representation internally.
+* The sketch algorithms are specialized for each separate field implementation, permitting inlining and specific optimizations while avoiding dynamic allocations and branching costs.
+* Decoding of sketches uses the [Berlekamp-Massey algorithm](https://en.wikipedia.org/w/index.php?title=Berlekamp%E2%80%93Massey_algorithm&oldid=870768940)<sup>[[3]](#myfootnote3)</sup> to compute the characteristic polynomial.
+* Finding the roots of polynomials is done using the Berlekamp trace algorithm with explicit formula for quadratic polynomials<sup>[[4]](#myfootnote4)</sup>. The root finding is randomized to prevent adversarial inputs that intentionally trigger worst-case decode time.
+* A (possibly) novel optimization combines a test for unique roots with the Berlekamp trace algorithm.
+
+Some improvements that are still TODO:
+* Explicit formulas for the roots of polynomials of higher degree than 2
+* Subquadratic multiplication and modulus algorithms
+* The [Half-GCD algorithm](http://mathworld.wolfram.com/Half-GCD.html) for faster GCDs
+* An interface for incremental decoding: most of the computation in most failed decodes can be reused when attempting to decode a longer sketch of the same set
+* Platform specific optimizations for platforms other than x86
+* Avoid using slow uint64_t for calculations on 32-bit hosts
+* Optional IBLT / Hybrid and set entropy coder under the same interface
+
+## References
+
+* <a name="myfootnote1">[1]</a> Dodis, Ostrovsky, Reyzin and Smith. *Fuzzy Extractors: How to Generate Strong Keys from Biometrics and Other Noisy Data.* SIAM Journal on Computing, volume 38, number 1, pages 97-139, 2008). [[URL]](http://eprint.iacr.org/2003/235) [[PDF]](https://eprint.iacr.org/2003/235.pdf)
+* <a name="myfootnote5">[5]</a> A. Trachtenberg, D. Starobinski and S. Agarwal. *Fast PDA synchronization using characteristic polynomial interpolation.* Proceedings, Twenty-First Annual Joint Conference of the IEEE Computer and Communications Societies, New York, NY, USA, 2002, pp. 1510-1519 vol.3. [[PDF]](https://pdfs.semanticscholar.org/43da/2070b6b7b2320a1fed2fd5e70e87332c9c5e.pdf)
+* <a name="myfootnote2">[2]</a> Cherly, Jørgen, Luis Gallardo, Leonid Vaserstein, and Ethel Wheland. *Solving quadratic equations over polynomial rings of characteristic two.* Publicacions Matemàtiques (1998): 131-142. [[PDF]](https://www.raco.cat/index.php/PublicacionsMatematiques/article/viewFile/37927/40412)
+* <a name="myfootnote3">[3]</a> J. Massey. *Shift-register synthesis and BCH decoding.* IEEE Transactions on Information Theory, vol. 15, no. 1, pp. 122-127, January 1969. [[PDF]](http://crypto.stanford.edu/~mironov/cs359/massey.pdf)
+* <a name="myfootnote4">[4]</a> Bhaskar Biswas, Vincent Herbert. *Efficient Root Finding of Polynomials over Fields of Characteristic 2.* 2009. hal-00626997. [[URL]](https://hal.archives-ouvertes.fr/hal-00626997) [[PDF]](https://hal.archives-ouvertes.fr/hal-00626997/document)
+* <a name="myfootnote6">[6]</a> Eppstein, David, Michael T. Goodrich, Frank Uyeda, and George Varghese. *What's the difference?: efficient set reconciliation without prior context.* ACM SIGCOMM Computer Communication Review, vol. 41, no. 4, pp. 218-229. ACM, 2011. [[PDF]](https://www.ics.uci.edu/~eppstein/pubs/EppGooUye-SIGCOMM-11.pdf)
+* <a name="myfootnote7">[7]</a> Goodrich, Michael T. and Michael Mitzenmacher. *Invertible bloom lookup tables.* 2011 49th Annual Allerton Conference on Communication, Control, and Computing (Allerton) (2011): 792-799. [[PDF]](https://arxiv.org/pdf/1101.2245.pdf)
+* <a name="myfootnote8">[8]</a> Maxwell, Gregory F. *[Blocksonly mode BW savings, the limits of efficient block xfer, and better relay](https://bitcointalk.org/index.php?topic=1377345.0)* Bitcointalk 2016, *[Technical notes on mempool synchronizing relay](https://nt4tn.net/tech-notes/2016.mempool_sync_relay.txt)* #bitcoin-wizards 2016.
+* <a name="myfootnote9">[9]</a> Maxwell, Gregory F. *[Block network coding](https://en.bitcoin.it/wiki/User:Gmaxwell/block_network_coding)* Bitcoin Wiki 2014, *[Technical notes on efficient block xfer](https://nt4tn.net/tech-notes/201512.efficient.block.xfer.txt)* #bitcoin-wizards 2015.
+* <a name="myfootnote10">[10]</a> Ruffing, Tim, Moreno-Sanchez, Pedro, Aniket, Kate, *P2P Mixing and Unlinkable Bitcoin Transactions* NDSS Symposium 2017 [[URL]](https://eprint.iacr.org/2016/824) [[PDF]](https://eprint.iacr.org/2016/824.pdf)
+* <a name="myfootnote11">[11]</a> Y. Misky, A. Trachtenberg, R. Zippel. *Set Reconciliation with Nearly Optimal Communication Complexity.* Cornell University, 2000. [[URL]](https://ecommons.cornell.edu/handle/1813/5803) [[PDF]](https://ecommons.cornell.edu/bitstream/handle/1813/5803/2000-1813.pdf)
+* <a name="myfootnote12">[12]</a> Itoh, Toshiya, and Shigeo Tsujii. "A fast algorithm for computing multiplicative inverses in GF (2m) using normal bases." Information and computation 78, no. 3 (1988): 171-177. [[URL]](https://www.sciencedirect.com/science/article/pii/0890540188900247)
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 00000000..27417daf
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# Copyright (c) 2013-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+set -e
+srcdir="$(dirname $0)"
+cd "$srcdir"
+if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then
+ LIBTOOLIZE="${GLIBTOOLIZE}"
+ export LIBTOOLIZE
+fi
+which autoreconf >/dev/null || \
+ (echo "configuration failed, please install autoconf first" && exit 1)
+autoreconf --install --force --warnings=all
diff --git a/build-aux/m4/ax_check_compile_flag.m4 b/build-aux/m4/ax_check_compile_flag.m4
new file mode 100644
index 00000000..bd753b34
--- /dev/null
+++ b/build-aux/m4/ax_check_compile_flag.m4
@@ -0,0 +1,53 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the current language's compiler
+# or gives an error. (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the current language's default
+# flags (e.g. CFLAGS) when the check is done. The check is thus made with
+# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
+# force the compiler to issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+ AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4
new file mode 100644
index 00000000..03a30ce4
--- /dev/null
+++ b/build-aux/m4/ax_check_link_flag.m4
@@ -0,0 +1,53 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the linker or gives an error.
+# (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the linker's default flags
+# when the check is done. The check is thus made with the flags: "LDFLAGS
+# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
+# issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_LINK_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_LINK_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
+AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $4 $1"
+ AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ LDFLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_LINK_FLAGS
diff --git a/build-aux/m4/ax_check_preproc_flag.m4 b/build-aux/m4/ax_check_preproc_flag.m4
new file mode 100644
index 00000000..e43560fb
--- /dev/null
+++ b/build-aux/m4/ax_check_preproc_flag.m4
@@ -0,0 +1,53 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_check_preproc_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_PREPROC_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the current language's
+# preprocessor or gives an error. (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the preprocessor's default
+# flags when the check is done. The check is thus made with the flags:
+# "CPPFLAGS EXTRA-FLAGS FLAG". This can for example be used to force the
+# preprocessor to issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_PREPROC_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{COMPILE,LINK}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_PREPROC_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]cppflags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG preprocessor accepts $1], CACHEVAR, [
+ ax_check_save_flags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $4 $1"
+ AC_PREPROC_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ CPPFLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_PREPROC_FLAGS
diff --git a/build-aux/m4/ax_cxx_compile_stdcxx.m4 b/build-aux/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 00000000..f7e51370
--- /dev/null
+++ b/build-aux/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,962 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the specified
+# version of the C++ standard. If necessary, add switches to CXX and
+# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
+# or '14' (for the C++14 standard).
+#
+# The second argument, if specified, indicates whether you insist on an
+# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+# -std=c++11). If neither is specified, you get whatever works, with
+# preference for no added switch, and then for an extended mode.
+#
+# The third argument, if specified 'mandatory' or if left unspecified,
+# indicates that baseline support for the specified C++ standard is
+# required and that the macro should error out if no mode with that
+# support is found. If specified 'optional', then configuration proceeds
+# regardless, after defining HAVE_CXX${VERSION} if and only if a
+# supporting mode is found.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+# Copyright (c) 2015 Paul Norman <penorman@mac.com>
+# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
+# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
+# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 12
+
+dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl (serial version number 13).
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+ m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+ [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+ [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+ [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$2], [], [],
+ [$2], [ext], [],
+ [$2], [noext], [],
+ [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+ [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+ AC_LANG_PUSH([C++])dnl
+ ac_success=no
+
+ m4_if([$2], [], [dnl
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+ ax_cv_cxx_compile_cxx$1,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [ax_cv_cxx_compile_cxx$1=yes],
+ [ax_cv_cxx_compile_cxx$1=no])])
+ if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+ ac_success=yes
+ fi])
+
+ m4_if([$2], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ switch="-std=gnu++${alternative}"
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$2], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ dnl HP's aCC needs +std=c++11 according to:
+ dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+ dnl Cray's crayCC needs "-h std=c++11"
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ if test x$ac_success = xyes; then
+ break
+ fi
+ done
+ fi])
+ AC_LANG_POP([C++])
+ if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+ if test x$ac_success = xno; then
+ AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+ fi
+ fi
+ if test x$ac_success = xno; then
+ HAVE_CXX$1=0
+ AC_MSG_NOTICE([No compiler with C++$1 support was found])
+ else
+ HAVE_CXX$1=1
+ AC_DEFINE(HAVE_CXX$1,1,
+ [define if the compiler supports basic C++$1 syntax])
+ fi
+ AC_SUBST(HAVE_CXX$1)
+])
+
+
+dnl Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+ namespace test_static_assert
+ {
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ }
+
+ namespace test_final_override
+ {
+
+ struct Base
+ {
+ virtual ~Base() {}
+ virtual void f() {}
+ };
+
+ struct Derived : public Base
+ {
+ virtual ~Derived() override {}
+ virtual void f() override {}
+ };
+
+ }
+
+ namespace test_double_right_angle_brackets
+ {
+
+ template < typename T >
+ struct check {};
+
+ typedef check<void> single_type;
+ typedef check<check<void>> double_type;
+ typedef check<check<check<void>>> triple_type;
+ typedef check<check<check<check<void>>>> quadruple_type;
+
+ }
+
+ namespace test_decltype
+ {
+
+ int
+ f()
+ {
+ int a = 1;
+ decltype(a) b = 2;
+ return a + b;
+ }
+
+ }
+
+ namespace test_type_deduction
+ {
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static const bool value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static const bool value = true;
+ };
+
+ template < typename T1, typename T2 >
+ auto
+ add(T1 a1, T2 a2) -> decltype(a1 + a2)
+ {
+ return a1 + a2;
+ }
+
+ int
+ test(const int c, volatile int v)
+ {
+ static_assert(is_same<int, decltype(0)>::value == true, "");
+ static_assert(is_same<int, decltype(c)>::value == false, "");
+ static_assert(is_same<int, decltype(v)>::value == false, "");
+ auto ac = c;
+ auto av = v;
+ auto sumi = ac + av + 'x';
+ auto sumf = ac + av + 1.0;
+ static_assert(is_same<int, decltype(ac)>::value == true, "");
+ static_assert(is_same<int, decltype(av)>::value == true, "");
+ static_assert(is_same<int, decltype(sumi)>::value == true, "");
+ static_assert(is_same<int, decltype(sumf)>::value == false, "");
+ static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+ return (sumf > 0.0) ? sumi : add(c, v);
+ }
+
+ }
+
+ namespace test_noexcept
+ {
+
+ int f() { return 0; }
+ int g() noexcept { return 0; }
+
+ static_assert(noexcept(f()) == false, "");
+ static_assert(noexcept(g()) == true, "");
+
+ }
+
+ namespace test_constexpr
+ {
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+ {
+ return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+ }
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c(const CharT *const s) noexcept
+ {
+ return strlen_c_r(s, 0UL);
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("1") == 1UL, "");
+ static_assert(strlen_c("example") == 7UL, "");
+ static_assert(strlen_c("another\0example") == 7UL, "");
+
+ }
+
+ namespace test_rvalue_references
+ {
+
+ template < int N >
+ struct answer
+ {
+ static constexpr int value = N;
+ };
+
+ answer<1> f(int&) { return answer<1>(); }
+ answer<2> f(const int&) { return answer<2>(); }
+ answer<3> f(int&&) { return answer<3>(); }
+
+ void
+ test()
+ {
+ int i = 0;
+ const int c = 0;
+ static_assert(decltype(f(i))::value == 1, "");
+ static_assert(decltype(f(c))::value == 2, "");
+ static_assert(decltype(f(0))::value == 3, "");
+ }
+
+ }
+
+ namespace test_uniform_initialization
+ {
+
+ struct test
+ {
+ static const int zero {};
+ static const int one {1};
+ };
+
+ static_assert(test::zero == 0, "");
+ static_assert(test::one == 1, "");
+
+ }
+
+ namespace test_lambdas
+ {
+
+ void
+ test1()
+ {
+ auto lambda1 = [](){};
+ auto lambda2 = lambda1;
+ lambda1();
+ lambda2();
+ }
+
+ int
+ test2()
+ {
+ auto a = [](int i, int j){ return i + j; }(1, 2);
+ auto b = []() -> int { return '0'; }();
+ auto c = [=](){ return a + b; }();
+ auto d = [&](){ return c; }();
+ auto e = [a, &b](int x) mutable {
+ const auto identity = [](int y){ return y; };
+ for (auto i = 0; i < a; ++i)
+ a += b--;
+ return x + identity(a + b);
+ }(0);
+ return a + b + c + d + e;
+ }
+
+ int
+ test3()
+ {
+ const auto nullary = [](){ return 0; };
+ const auto unary = [](int x){ return x; };
+ using nullary_t = decltype(nullary);
+ using unary_t = decltype(unary);
+ const auto higher1st = [](nullary_t f){ return f(); };
+ const auto higher2nd = [unary](nullary_t f1){
+ return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+ };
+ return higher1st(nullary) + higher2nd(nullary)(unary);
+ }
+
+ }
+
+ namespace test_variadic_templates
+ {
+
+ template <int...>
+ struct sum;
+
+ template <int N0, int... N1toN>
+ struct sum<N0, N1toN...>
+ {
+ static constexpr auto value = N0 + sum<N1toN...>::value;
+ };
+
+ template <>
+ struct sum<>
+ {
+ static constexpr auto value = 0;
+ };
+
+ static_assert(sum<>::value == 0, "");
+ static_assert(sum<1>::value == 1, "");
+ static_assert(sum<23>::value == 23, "");
+ static_assert(sum<1, 2>::value == 3, "");
+ static_assert(sum<5, 5, 11>::value == 21, "");
+ static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+ }
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+ // because of this.
+ namespace test_template_alias_sfinae
+ {
+
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() { func<foo>(0); }
+
+ }
+
+} // namespace cxx11
+
+#endif // __cplusplus >= 201103L
+
+]])
+
+
+dnl Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+ namespace test_polymorphic_lambdas
+ {
+
+ int
+ test()
+ {
+ const auto lambda = [](auto&&... args){
+ const auto istiny = [](auto x){
+ return (sizeof(x) == 1UL) ? 1 : 0;
+ };
+ const int aretiny[] = { istiny(args)... };
+ return aretiny[0];
+ };
+ return lambda(1, 1L, 1.0f, '1');
+ }
+
+ }
+
+ namespace test_binary_literals
+ {
+
+ constexpr auto ivii = 0b0000000000101010;
+ static_assert(ivii == 42, "wrong value");
+
+ }
+
+ namespace test_generalized_constexpr
+ {
+
+ template < typename CharT >
+ constexpr unsigned long
+ strlen_c(const CharT *const s) noexcept
+ {
+ auto length = 0UL;
+ for (auto p = s; *p; ++p)
+ ++length;
+ return length;
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("x") == 1UL, "");
+ static_assert(strlen_c("test") == 4UL, "");
+ static_assert(strlen_c("another\0test") == 7UL, "");
+
+ }
+
+ namespace test_lambda_init_capture
+ {
+
+ int
+ test()
+ {
+ auto x = 0;
+ const auto lambda1 = [a = x](int b){ return a + b; };
+ const auto lambda2 = [a = lambda1(x)](){ return a; };
+ return lambda2();
+ }
+
+ }
+
+ namespace test_digit_separators
+ {
+
+ constexpr auto ten_million = 100'000'000;
+ static_assert(ten_million == 100000000, "");
+
+ }
+
+ namespace test_return_type_deduction
+ {
+
+ auto f(int& x) { return x; }
+ decltype(auto) g(int& x) { return x; }
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static constexpr auto value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static constexpr auto value = true;
+ };
+
+ int
+ test()
+ {
+ auto x = 0;
+ static_assert(is_same<int, decltype(f(x))>::value, "");
+ static_assert(is_same<int&, decltype(g(x))>::value, "");
+ return x;
+ }
+
+ }
+
+} // namespace cxx14
+
+#endif // __cplusplus >= 201402L
+
+]])
+
+
+dnl Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201703L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+ namespace test_constexpr_lambdas
+ {
+
+ constexpr int foo = [](){return 42;}();
+
+ }
+
+ namespace test::nested_namespace::definitions
+ {
+
+ }
+
+ namespace test_fold_expression
+ {
+
+ template<typename... Args>
+ int multiply(Args... args)
+ {
+ return (args * ... * 1);
+ }
+
+ template<typename... Args>
+ bool all(Args... args)
+ {
+ return (args && ...);
+ }
+
+ }
+
+ namespace test_extended_static_assert
+ {
+
+ static_assert (true);
+
+ }
+
+ namespace test_auto_brace_init_list
+ {
+
+ auto foo = {5};
+ auto bar {5};
+
+ static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+ static_assert(std::is_same<int, decltype(bar)>::value);
+ }
+
+ namespace test_typename_in_template_template_parameter
+ {
+
+ template<template<typename> typename X> struct D;
+
+ }
+
+ namespace test_fallthrough_nodiscard_maybe_unused_attributes
+ {
+
+ int f1()
+ {
+ return 42;
+ }
+
+ [[nodiscard]] int f2()
+ {
+ [[maybe_unused]] auto unused = f1();
+
+ switch (f1())
+ {
+ case 17:
+ f1();
+ [[fallthrough]];
+ case 42:
+ f1();
+ }
+ return f1();
+ }
+
+ }
+
+ namespace test_extended_aggregate_initialization
+ {
+
+ struct base1
+ {
+ int b1, b2 = 42;
+ };
+
+ struct base2
+ {
+ base2() {
+ b3 = 42;
+ }
+ int b3;
+ };
+
+ struct derived : base1, base2
+ {
+ int d;
+ };
+
+ derived d1 {{1, 2}, {}, 4}; // full initialization
+ derived d2 {{}, {}, 4}; // value-initialized bases
+
+ }
+
+ namespace test_general_range_based_for_loop
+ {
+
+ struct iter
+ {
+ int i;
+
+ int& operator* ()
+ {
+ return i;
+ }
+
+ const int& operator* () const
+ {
+ return i;
+ }
+
+ iter& operator++()
+ {
+ ++i;
+ return *this;
+ }
+ };
+
+ struct sentinel
+ {
+ int i;
+ };
+
+ bool operator== (const iter& i, const sentinel& s)
+ {
+ return i.i == s.i;
+ }
+
+ bool operator!= (const iter& i, const sentinel& s)
+ {
+ return !(i == s);
+ }
+
+ struct range
+ {
+ iter begin() const
+ {
+ return {0};
+ }
+
+ sentinel end() const
+ {
+ return {5};
+ }
+ };
+
+ void f()
+ {
+ range r {};
+
+ for (auto i : r)
+ {
+ [[maybe_unused]] auto v = i;
+ }
+ }
+
+ }
+
+ namespace test_lambda_capture_asterisk_this_by_value
+ {
+
+ struct t
+ {
+ int i;
+ int foo()
+ {
+ return [*this]()
+ {
+ return i;
+ }();
+ }
+ };
+
+ }
+
+ namespace test_enum_class_construction
+ {
+
+ enum class byte : unsigned char
+ {};
+
+ byte foo {42};
+
+ }
+
+ namespace test_constexpr_if
+ {
+
+ template <bool cond>
+ int f ()
+ {
+ if constexpr(cond)
+ {
+ return 13;
+ }
+ else
+ {
+ return 42;
+ }
+ }
+
+ }
+
+ namespace test_selection_statement_with_initializer
+ {
+
+ int f()
+ {
+ return 13;
+ }
+
+ int f2()
+ {
+ if (auto i = f(); i > 0)
+ {
+ return 3;
+ }
+
+ switch (auto i = f(); i + 4)
+ {
+ case 17:
+ return 2;
+
+ default:
+ return 1;
+ }
+ }
+
+ }
+
+ namespace test_template_argument_deduction_for_class_templates
+ {
+
+ template <typename T1, typename T2>
+ struct pair
+ {
+ pair (T1 p1, T2 p2)
+ : m1 {p1},
+ m2 {p2}
+ {}
+
+ T1 m1;
+ T2 m2;
+ };
+
+ void f()
+ {
+ [[maybe_unused]] auto p = pair{13, 42u};
+ }
+
+ }
+
+ namespace test_non_type_auto_template_parameters
+ {
+
+ template <auto n>
+ struct B
+ {};
+
+ B<5> b1;
+ B<'a'> b2;
+
+ }
+
+ namespace test_structured_bindings
+ {
+
+ int arr[2] = { 1, 2 };
+ std::pair<int, int> pr = { 1, 2 };
+
+ auto f1() -> int(&)[2]
+ {
+ return arr;
+ }
+
+ auto f2() -> std::pair<int, int>&
+ {
+ return pr;
+ }
+
+ struct S
+ {
+ int x1 : 2;
+ volatile double y1;
+ };
+
+ S f3()
+ {
+ return {};
+ }
+
+ auto [ x1, y1 ] = f1();
+ auto& [ xr1, yr1 ] = f1();
+ auto [ x2, y2 ] = f2();
+ auto& [ xr2, yr2 ] = f2();
+ const auto [ x3, y3 ] = f3();
+
+ }
+
+ namespace test_exception_spec_type_system
+ {
+
+ struct Good {};
+ struct Bad {};
+
+ void g1() noexcept;
+ void g2();
+
+ template<typename T>
+ Bad
+ f(T*, T*);
+
+ template<typename T1, typename T2>
+ Good
+ f(T1*, T2*);
+
+ static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+ }
+
+ namespace test_inline_variables
+ {
+
+ template<class T> void f(T)
+ {}
+
+ template<class T> inline T g(T)
+ {
+ return T{};
+ }
+
+ template<> inline void f<>(int)
+ {}
+
+ template<> int g<>(int)
+ {
+ return 5;
+ }
+
+ }
+
+} // namespace cxx17
+
+#endif // __cplusplus < 201703L
+
+]])
diff --git a/ci/cirrus.sh b/ci/cirrus.sh
new file mode 100755
index 00000000..36250d16
--- /dev/null
+++ b/ci/cirrus.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+set -e
+set -x
+
+export LC_ALL=C
+
+env >> test_env.log
+
+$CXX -v || true
+valgrind --version || true
+
+./autogen.sh
+
+FIELDS=
+if [ -n "$ENABLE_FIELDS" ]; then
+ FIELDS="--enable-fields=$ENABLE_FIELDS"
+fi
+./configure --host="$HOST" --enable-benchmark="$BENCH" $FIELDS
+
+# We have set "-j<n>" in MAKEFLAGS.
+make
+
+# Print information about binaries so that we can see that the architecture is correct
+file test* || true
+file bench* || true
+file .libs/* || true
+
+if [ -n "$BUILD" ]
+then
+ make "$BUILD"
+fi
+
+if [ -n "$EXEC_CMD" ]; then
+ $EXEC_CMD "./test$EXEC_EXT" $TESTRUNS
+ $EXEC_CMD "./test-verify$EXEC_EXT" $TESTRUNS
+fi
+
+if [ "$BENCH" = "yes" ]; then
+ $EXEC_CMD "./bench$EXEC_EXT"
+fi
diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile
new file mode 100644
index 00000000..122af36e
--- /dev/null
+++ b/ci/linux-debian.Dockerfile
@@ -0,0 +1,17 @@
+FROM debian:stable
+
+RUN dpkg --add-architecture i386
+RUN dpkg --add-architecture s390x
+RUN apt-get update
+
+# dkpg-dev: to make pkg-config work in cross-builds
+RUN apt-get install --no-install-recommends --no-upgrade -y \
+ git ca-certificates \
+ make automake libtool pkg-config dpkg-dev valgrind qemu-user \
+ gcc g++ clang libclang-rt-dev libc6-dbg \
+ gcc-i686-linux-gnu g++-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 \
+ g++-s390x-linux-gnu libstdc++6:s390x gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \
+ wine wine64 g++-mingw-w64-x86-64
+
+# Run a dummy command in wine to make it set up configuration
+RUN wine true || true
diff --git a/cmake/PrintConfigureSummary.cmake b/cmake/PrintConfigureSummary.cmake
new file mode 100644
index 00000000..ba03cc82
--- /dev/null
+++ b/cmake/PrintConfigureSummary.cmake
@@ -0,0 +1,112 @@
+include_guard(GLOBAL)
+
+function(indent_message header content indent_num)
+ if(indent_num GREATER 0)
+ string(REPEAT " " ${indent_num} indentation)
+ string(REPEAT "." ${indent_num} tail)
+ string(REGEX REPLACE "${tail}$" "" header "${header}")
+ endif()
+ message("${indentation}${header} ${content}")
+endfunction()
+
+# Print compiler's flags on best-effort. Include the abstracted
+# CMake flags that we touch ourselves.
+function(print_flags_per_config config indent_num)
+ string(STRIP "${CMAKE_CXX_COMPILER_ARG1} ${CMAKE_CXX_FLAGS}" combined_cxx_flags)
+ string(TOUPPER "${config}" config_uppercase)
+ string(STRIP "${combined_cxx_flags} ${CMAKE_CXX_FLAGS_${config_uppercase}}" combined_cxx_flags)
+ string(STRIP "${combined_cxx_flags} ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION}" combined_cxx_flags)
+ if(CMAKE_POSITION_INDEPENDENT_CODE)
+ string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${CMAKE_CXX_COMPILE_OPTIONS_PIC})
+ endif()
+ if(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY AND CMAKE_CXX_VISIBILITY_PRESET)
+ string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY}${CMAKE_CXX_VISIBILITY_PRESET})
+ endif()
+ get_directory_property(compile_options COMPILE_OPTIONS)
+ string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${compile_options})
+ indent_message("CXXFLAGS .............................." "${combined_cxx_flags}" ${indent_num})
+endfunction()
+
+function(print_configure_summary)
+ message("")
+ if(PROJECT_IS_TOP_LEVEL)
+ message("Configure summary")
+ message("=================")
+ else()
+ message("minisketch configure summary")
+ message("============================")
+ endif()
+ if(BUILD_SHARED_LIBS)
+ set(library_type "Shared")
+ else()
+ set(library_type "Static")
+ endif()
+ message("Library type .......................... ${library_type}")
+ message("Build options:")
+ if(have_disabled_fields)
+ set(filed_sizes "${MINISKETCH_FIELDS}")
+ else()
+ set(filed_sizes "All")
+ endif()
+ message(" field sizes ........................ ${filed_sizes}")
+ if(HAVE_CLMUL)
+ set(clmul_status "Enabled")
+ else()
+ set(clmul_status "Disabled")
+ endif()
+ message(" clmul fields ........................ ${clmul_status}")
+ if(CMAKE_CXX_STANDARD GREATER_EQUAL 20)
+ set(clz_status "C++20")
+ elseif(HAVE_CLZ)
+ set(clz_status "Compiler builtin")
+ else()
+ set(clz_status "Default")
+ endif()
+ message(" clz implementation .................. ${clz_status}")
+ message("Optional binaries:")
+ message(" benchmark ........................... ${MINISKETCH_BUILD_BENCHMARK}")
+ message(" tests ............................... ${MINISKETCH_BUILD_TESTS}")
+ message("")
+ if(CMAKE_CROSSCOMPILING)
+ set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
+ else()
+ set(cross_status "FALSE")
+ endif()
+ message("Cross compiling ....................... ${cross_status}")
+ message("C++ compiler .......................... ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}, ${CMAKE_CXX_COMPILER}")
+ get_property(_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_is_multi_config)
+ list(JOIN CMAKE_CONFIGURATION_TYPES ", " configs)
+ message("Available build configurations ........ ${configs}")
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(default_config "Debug")
+ else()
+ list(GET CMAKE_CONFIGURATION_TYPES 0 default_config)
+ endif()
+ message("Default build configuration ........... ${default_config}")
+ foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES)
+ message("'${config}' build configuration:")
+ print_flags_per_config("${config}" 2)
+ endforeach()
+ else()
+ message("CMAKE_BUILD_TYPE ...................... ${CMAKE_BUILD_TYPE}")
+ print_flags_per_config("${CMAKE_BUILD_TYPE}" 0)
+ endif()
+ unset(_is_multi_config)
+
+ message([=[
+
+NOTE: The summary above may not exactly match the final applied build flags
+ if any additional CMAKE_* or environment variables have been modified.
+ To see the exact flags applied, build with the --verbose option.]=]
+ )
+
+ if(have_disabled_fields AND PROJECT_IS_TOP_LEVEL)
+ message("")
+ message(WARNING
+ "Only compiling in support for field sizes: ${MINISKETCH_FIELDS}\n"
+ "This means the library will lack support for other field sizes entirely.\n"
+ )
+ endif()
+ message("")
+endfunction()
diff --git a/cmake/SystemIntrospection.cmake b/cmake/SystemIntrospection.cmake
new file mode 100644
index 00000000..9e6cbfd4
--- /dev/null
+++ b/cmake/SystemIntrospection.cmake
@@ -0,0 +1,43 @@
+include_guard(GLOBAL)
+
+include(CheckCXXSourceCompiles)
+include(CMakePushCheckState)
+cmake_push_check_state(RESET)
+
+# Check for clmul instructions support.
+if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ set(CMAKE_REQUIRED_FLAGS "-mpclmul")
+endif()
+check_cxx_source_compiles("
+ #include <immintrin.h>
+ #include <stdint.h>
+
+ int main()
+ {
+ __m128i a = _mm_cvtsi64_si128((uint64_t)7);
+ __m128i b = _mm_clmulepi64_si128(a, a, 37);
+ __m128i c = _mm_srli_epi64(b, 41);
+ __m128i d = _mm_xor_si128(b, c);
+ uint64_t e = _mm_cvtsi128_si64(d);
+ return e == 0;
+ }
+ " HAVE_CLMUL
+)
+if(HAVE_CLMUL)
+ set(CLMUL_CXXFLAGS ${CMAKE_REQUIRED_FLAGS})
+endif()
+
+if(CMAKE_CXX_STANDARD LESS 20)
+ # Check for working clz builtins.
+ check_cxx_source_compiles("
+ int main()
+ {
+ unsigned a = __builtin_clz(1);
+ unsigned long b = __builtin_clzl(1);
+ unsigned long long c = __builtin_clzll(1);
+ }
+ " HAVE_CLZ
+ )
+endif()
+
+cmake_pop_check_state()
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 00000000..ec1815d9
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,154 @@
+AC_INIT([minisketch], [0.0.1], [http://github.com/bitcoin-core/minisketch/])
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_PREREQ(2.60)
+AC_CONFIG_SRCDIR([src/minisketch.cpp])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIR([build-aux/m4])
+AM_INIT_AUTOMAKE([subdir-objects foreign])
+
+LT_INIT
+LT_LANG([C++])
+AC_LANG([C++])
+
+AC_PATH_PROG(CCACHE,ccache)
+
+AC_ARG_ENABLE([ccache],
+ [AS_HELP_STRING([--disable-ccache],
+ [do not use ccache for building (default is to use if found)])],
+ [use_ccache=$enableval],
+ [use_ccache=auto])
+
+AC_ARG_ENABLE(tests,
+ AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
+ [use_tests=$enableval],
+ [use_tests=yes])
+
+AC_ARG_ENABLE(benchmark,
+ AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
+ [use_benchmark=$enableval],
+ [use_benchmark=no])
+
+m4_define([SUPPORTED_FIELDS], [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64])
+
+AC_MSG_CHECKING([which field sizes to build])
+AC_ARG_ENABLE([fields], AS_HELP_STRING([--enable-fields=LIST], [Comma-separated list of field sizes to build. Default=all. Available sizes:] m4_translit(m4_defn([SUPPORTED_FIELDS]), [,], [ ])), [], [enable_fields=SUPPORTED_FIELDS])
+have_disabled_fields=no
+have_enabled_fields=no
+m4_foreach([FIELD], [SUPPORTED_FIELDS], [
+ case ",$enable_fields," in
+ *,FIELD,*)
+ have_enabled_fields=yes
+ ;;
+ *)
+ AC_DEFINE(DISABLE_FIELD_[]FIELD, [1],
+ [Define to 1 to remove support for field size] FIELD [.])
+ have_disabled_fields=yes
+ ;;
+ esac
+])
+AC_MSG_RESULT([$enable_fields])
+if test "x$have_enabled_fields" = xno; then
+ AC_MSG_ERROR([No field sizes are enabled.])
+fi
+
+AX_CHECK_COMPILE_FLAG([-Werror],[CXXFLAG_WERROR="-Werror"],[CXXFLAG_WERROR=""])
+
+AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory])
+enable_clmul=
+AX_CHECK_COMPILE_FLAG([-mpclmul],[[enable_clmul=yes]],,[[$CXXFLAG_WERROR]],[AC_LANG_PROGRAM([
+ #include <stdint.h>
+ #include <x86intrin.h>
+], [
+ __m128i a = _mm_cvtsi64_si128((uint64_t)7);
+ __m128i b = _mm_clmulepi64_si128(a, a, 37);
+ __m128i c = _mm_srli_epi64(b, 41);
+ __m128i d = _mm_xor_si128(b, c);
+ uint64_t e = _mm_cvtsi128_si64(d);
+ return e == 0;
+])])
+if test x$enable_clmul = xyes; then
+ CLMUL_CXXFLAGS="-mpclmul"
+ AC_DEFINE(HAVE_CLMUL, 1, [Define this symbol if clmul instructions can be used])
+fi
+
+
+AC_MSG_CHECKING(for working clz builtins)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
+ unsigned a = __builtin_clz(1);
+ unsigned long b = __builtin_clzl(1);
+ unsigned long long c = __builtin_clzll(1);
+ ])],
+ [
+ AC_DEFINE(HAVE_CLZ, 1, [Define this symbol if clz builtins are present and working])
+ AC_MSG_RESULT(yes)
+ ],[
+ AC_MSG_RESULT(no)
+ ]
+)
+
+AX_CHECK_LINK_FLAG([[-Wl,--exclude-libs,ALL]],[LDFLAGS="-Wl,--exclude-libs,ALL $LDFLAGS"])
+
+case $host in
+ *mingw*)
+ dnl -static is interpreted by libtool, where it has a different meaning.
+ dnl In libtool-speak, it's -all-static.
+ AX_CHECK_LINK_FLAG([[-static]],[LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"])
+ ;;
+ *)
+ AX_CHECK_LINK_FLAG([[-static]],[LIBTOOL_APP_LDFLAGS="-static"])
+ ;;
+esac
+
+AX_CHECK_COMPILE_FLAG([-Wall],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]])
+AX_CHECK_COMPILE_FLAG([-Wundef], [WARN_CXXFLAGS="$WARN_CXXFLAGS -Wundef"], [], [$CXXFLAG_WERROR])
+AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],[CXXFLAGS="$CXXFLAGS -fvisibility=hidden"],[],[$CXXFLAG_WERROR])
+
+if test "x$use_ccache" != "xno"; then
+ AC_MSG_CHECKING(if ccache should be used)
+ if test x$CCACHE = x; then
+ if test "x$use_ccache" = "xyes"; then
+ AC_MSG_ERROR([ccache not found.]);
+ else
+ use_ccache=no
+ fi
+ else
+ use_ccache=yes
+ CXX="$ac_cv_path_CCACHE $CXX"
+ fi
+ AC_MSG_RESULT($use_ccache)
+fi
+
+VERIFY_DEFINES=-DMINISKETCH_VERIFY
+RELEASE_DEFINES=
+
+AC_CONFIG_FILES([
+ Makefile
+])
+
+AC_SUBST(CLMUL_CXXFLAGS)
+AC_SUBST(WARN_CXXFLAGS)
+AC_SUBST(NOWARN_CXXFLAGS)
+AC_SUBST(VERIFY_DEFINES)
+AC_SUBST(RELEASE_DEFINES)
+AC_SUBST(LIBTOOL_APP_LDFLAGS)
+AM_CONDITIONAL([ENABLE_CLMUL],[test x$enable_clmul = xyes])
+AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
+AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
+AC_OUTPUT
+
+echo
+echo "Build Options:"
+echo " with benchmarks = $use_benchmark"
+echo " with tests = $use_tests"
+echo " enable clmul fields = $enable_clmul"
+echo " CXX = $CXX"
+echo " CXXFLAGS = $CXXFLAGS"
+echo " CPPFLAGS = $CPPFLAGS"
+echo " LDFLAGS = $LDFLAGS"
+if test "$have_disabled_fields" = "yes"; then
+echo
+echo "Only compiling in support for field sizes: $enable_fields"
+echo "WARNING: this means the library will lack support for other field sizes entirely"
+fi
diff --git a/doc/example.c b/doc/example.c
new file mode 100644
index 00000000..72791658
--- /dev/null
+++ b/doc/example.c
@@ -0,0 +1,51 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include <stdio.h>
+#include <assert.h>
+#include "../include/minisketch.h"
+
+int main(void) {
+
+ minisketch *sketch_a = minisketch_create(12, 0, 4);
+
+ for (int i = 3000; i < 3010; ++i) {
+ minisketch_add_uint64(sketch_a, i);
+ }
+
+ size_t sersize = minisketch_serialized_size(sketch_a);
+ assert(sersize == 12 * 4 / 8); // 4 12-bit values is 6 bytes.
+ unsigned char *buffer_a = malloc(sersize);
+ minisketch_serialize(sketch_a, buffer_a);
+ minisketch_destroy(sketch_a);
+
+ minisketch *sketch_b = minisketch_create(12, 0, 4); // Bob's own sketch
+ for (int i = 3002; i < 3012; ++i) {
+ minisketch_add_uint64(sketch_b, i);
+ }
+
+ sketch_a = minisketch_create(12, 0, 4); // Alice's sketch
+ minisketch_deserialize(sketch_a, buffer_a); // Load Alice's sketch
+ free(buffer_a);
+
+ // Merge the elements from sketch_a into sketch_b. The result is a sketch_b
+ // which contains all elements that occurred in Alice's or Bob's sets, but not
+ // in both.
+ minisketch_merge(sketch_b, sketch_a);
+
+ uint64_t differences[4];
+ ssize_t num_differences = minisketch_decode(sketch_b, 4, differences);
+ minisketch_destroy(sketch_a);
+ minisketch_destroy(sketch_b);
+ if (num_differences < 0) {
+ printf("More than 4 differences!\n");
+ } else {
+ ssize_t i;
+ for (i = 0; i < num_differences; ++i) {
+ printf("%u is in only one of the two sets\n", (unsigned)differences[i]);
+ }
+ }
+}
diff --git a/doc/gen_basefpbits.sage b/doc/gen_basefpbits.sage
new file mode 100644
index 00000000..d1e75a6e
--- /dev/null
+++ b/doc/gen_basefpbits.sage
@@ -0,0 +1,78 @@
+# Require exact values up to
+FPBITS = 256
+
+# Overkill accuracy
+F = RealField(400)
+
+def BaseFPBits(bits, capacity):
+ return bits * capacity - int(ceil(F(log(sum(binomial(2**bits - 1, i) for i in range(capacity+1)), 2))))
+
+def Log2Factorial(capacity):
+ return int(floor(log(factorial(capacity), 2)))
+
+print("uint64_t BaseFPBits(uint32_t bits, uint32_t capacity) {")
+print(" // Correction table for low bits/capacities")
+TBLS={}
+FARS={}
+SKIPS={}
+for bits in range(1, 32):
+ TBL = []
+ for capacity in range(1, min(2**bits, FPBITS)):
+ exact = BaseFPBits(bits, capacity)
+ approx = Log2Factorial(capacity)
+ TBL.append((exact, approx))
+ MIN = 10000000000
+ while len(TBL) and ((TBL[-1][0] == TBL[-1][1]) or (TBL[-1][0] >= FPBITS and TBL[-1][1] >= FPBITS)):
+ MIN = min(MIN, TBL[-1][0] - TBL[-1][1])
+ TBL.pop()
+ while len(TBL) and (TBL[-1][0] - TBL[-1][1] == MIN):
+ TBL.pop()
+ SKIP = 0
+ while SKIP < len(TBL) and TBL[SKIP][0] == TBL[SKIP][1]:
+ SKIP += 1
+ DIFFS = [TBL[i][0] - TBL[i][1] for i in range(SKIP, len(TBL))]
+ if len(DIFFS) > 0 and len(DIFFS) * Integer(max(DIFFS)).nbits() > 64:
+ print(" static constexpr uint8_t ADD%i[] = {%s};" % (bits, ", ".join(("%i" % (TBL[i][0] - TBL[i][1])) for i in range(SKIP, len(TBL)))))
+ TBLS[bits] = DIFFS
+ FARS[bits] = MIN
+ SKIPS[bits] = SKIP
+print("")
+print(" if (capacity == 0) return 0;")
+print(" uint64_t ret = 0;")
+print(" if (bits < 32 && capacity >= (1U << bits)) {")
+print(" ret = uint64_t{bits} * (capacity - (1U << bits) + 1);")
+print(" capacity = (1U << bits) - 1;")
+print(" }")
+print(" ret += Log2Factorial(capacity);")
+print(" switch (bits) {")
+for bits in sorted(TBLS.keys()):
+ if len(TBLS[bits]) == 0:
+ continue
+ width = Integer(max(TBLS[bits])).nbits()
+ if len(TBLS[bits]) == 1:
+ add = "%i" % TBLS[bits][0]
+ elif len(TBLS[bits]) * width <= 64:
+ code = sum((2**(width*i) * TBLS[bits][i]) for i in range(len(TBLS[bits])))
+ if width == 1:
+ add = "(0x%x >> (capacity - %i)) & 1" % (code, 1 + SKIPS[bits])
+ else:
+ add = "(0x%x >> %i * (capacity - %i)) & %i" % (code, width, 1 + SKIPS[bits], 2**width - 1)
+ else:
+ add = "ADD%i[capacity - %i]" % (bits, 1 + SKIPS[bits])
+ if len(TBLS[bits]) + SKIPS[bits] == 2**bits - 1:
+ print(" case %i: return ret + (capacity <= %i ? 0 : %s);" % (bits, SKIPS[bits], add))
+ else:
+ print(" case %i: return ret + (capacity <= %i ? 0 : capacity > %i ? %i : %s);" % (bits, SKIPS[bits], len(TBLS[bits]) + SKIPS[bits], FARS[bits], add))
+print(" default: return ret;")
+print(" }")
+print("}")
+
+print("void TestBaseFPBits() {")
+print(" static constexpr uint16_t TBL[20][100] = {%s};" % (", ".join("{" + ", ".join(("%i" % BaseFPBits(bits, capacity)) for capacity in range(0, 100)) + "}" for bits in range(1, 21))))
+print(" for (int bits = 1; bits <= 20; ++bits) {")
+print(" for (int capacity = 0; capacity < 100; ++capacity) {")
+print(" uint64_t computed = BaseFPBits(bits, capacity), exact = TBL[bits - 1][capacity];")
+print(" CHECK(exact == computed || (exact >= 256 && computed >= 256));")
+print(" }")
+print(" }")
+print("}")
diff --git a/doc/gen_params.sage b/doc/gen_params.sage
new file mode 100755
index 00000000..1cf036ad
--- /dev/null
+++ b/doc/gen_params.sage
@@ -0,0 +1,333 @@
+#!/usr/bin/env sage
+r"""
+Generate finite field parameters for minisketch.
+
+This script selects the finite fields used by minisketch
+ for various sizes and generates the required tables for
+ the implementation.
+
+The output (after formatting) can be found in src/fields/*.cpp.
+
+"""
+B.<b> = GF(2)
+P.<p> = B[]
+
+def apply_map(m, v):
+ r = 0
+ i = 0
+ while v != 0:
+ if (v & 1):
+ r ^^= m[i]
+ i += 1
+ v >>= 1
+ return r
+
+def recurse_moduli(acc, maxweight, maxdegree):
+ for pos in range(maxweight, maxdegree + 1, 1):
+ poly = acc + p^pos
+ if maxweight == 1:
+ if poly.is_irreducible():
+ return (pos, poly)
+ else:
+ (deg, ret) = recurse_moduli(poly, maxweight - 1, pos - 1)
+ if ret is not None:
+ return (pos, ret)
+ return (None, None)
+
+def compute_moduli(bits):
+ # Return all optimal irreducible polynomials for GF(2^bits)
+ # The result is a list of tuples (weight, degree of second-highest nonzero coefficient, polynomial)
+ maxdegree = bits - 1
+ result = []
+ for weight in range(1, bits, 2):
+ deg, res = None, None
+ while True:
+ ret = recurse_moduli(p^bits + 1, weight, maxdegree)
+ if ret[0] is not None:
+ (deg, res) = ret
+ maxdegree = deg - 1
+ else:
+ break
+ if res is not None:
+ result.append((weight + 2, deg, res))
+ return result
+
+def bits_to_int(vals):
+ ret = 0
+ base = 1
+ for val in vals:
+ ret += Integer(val) * base
+ base *= 2
+ return ret
+
+def sqr_table(f, bits, n=1):
+ ret = []
+ for i in range(bits):
+ ret.append((f^(2^n*i)).integer_representation())
+ return ret
+
+# Compute x**(2**n)
+def pow2(x, n):
+ for i in range(n):
+ x = x**2
+ return x
+
+def qrt_table(F, f, bits):
+ # Table for solving x2 + x = a
+ # This implements the technique from https://www.raco.cat/index.php/PublicacionsMatematiques/article/viewFile/37927/40412, Lemma 1
+ for i in range(bits):
+ if (f**i).trace() != 0:
+ u = f**i
+ ret = []
+ for i in range(0, bits):
+ d = f^i
+ y = sum(pow2(d, j) * sum(pow2(u, k) for k in range(j)) for j in range(1, bits))
+ ret.append(y.integer_representation() ^^ (y.integer_representation() & 1))
+ return ret
+
+def conv_tables(F, NF, bits):
+ # Generate a F(2) linear projection that maps elements from one field
+ # to an isomorphic field with a different modulus.
+ f = F.gen()
+ fp = f.minimal_polynomial()
+ assert(fp == F.modulus())
+ nfp = fp.change_ring(NF)
+ nf = sorted(nfp.roots(multiplicities=False))[0]
+ ret = []
+ matrepr = [[B(0) for x in range(bits)] for y in range(bits)]
+ for i in range(bits):
+ val = (nf**i).integer_representation()
+ ret.append(val)
+ for j in range(bits):
+ matrepr[j][i] = B((val >> j) & 1)
+ mat = Matrix(matrepr).inverse().transpose()
+ ret2 = []
+ for i in range(bits):
+ ret2.append(bits_to_int(mat[i]))
+
+ for t in range(100):
+ f1a = F.random_element()
+ f1b = F.random_element()
+ f1r = f1a * f1b
+ f2a = NF.fetch_int(apply_map(ret, f1a.integer_representation()))
+ f2b = NF.fetch_int(apply_map(ret, f1b.integer_representation()))
+ f2r = NF.fetch_int(apply_map(ret, f1r.integer_representation()))
+ f2s = f2a * f2b
+ assert(f2r == f2s)
+
+ for t in range(100):
+ f2a = NF.random_element()
+ f2b = NF.random_element()
+ f2r = f2a * f2b
+ f1a = F.fetch_int(apply_map(ret2, f2a.integer_representation()))
+ f1b = F.fetch_int(apply_map(ret2, f2b.integer_representation()))
+ f1r = F.fetch_int(apply_map(ret2, f2r.integer_representation()))
+ f1s = f1a * f1b
+ assert(f1r == f1s)
+
+ return (ret, ret2)
+
+def fmt(i,typ):
+ if i == 0:
+ return "0"
+ else:
+ return "0x%x" % i
+
+def lintranstype(typ, bits, maxtbl):
+ gsize = min(maxtbl, bits)
+ array_size = (bits + gsize - 1) // gsize
+ bits_list = []
+ total = 0
+ for i in range(array_size):
+ rsize = (bits - total + array_size - i - 1) // (array_size - i)
+ total += rsize
+ bits_list.append(rsize)
+ return "RecLinTrans<%s, %s>" % (typ, ", ".join("%i" % x for x in bits_list))
+
+INT=0
+CLMUL=1
+CLMUL_TRI=2
+MD=3
+
+def print_modulus_md(mod):
+ ret = ""
+ pos = mod.degree()
+ for c in reversed(list(mod)):
+ if c:
+ if ret:
+ ret += " + "
+ if pos == 0:
+ ret += "1"
+ elif pos == 1:
+ ret += "x"
+ else:
+ ret += "x<sup>%i</sup>" % pos
+ pos -= 1
+ return ret
+
+def pick_modulus(bits, style):
+ # Choose the lexicographicly-first lowest-weight modulus
+ # optionally subject to implementation specific constraints.
+ moduli = compute_moduli(bits)
+ if style == INT or style == MD:
+ multi_sqr = False
+ need_trans = False
+ elif style == CLMUL:
+ # Fast CLMUL reduction requires that bits + the highest
+ # set bit are less than 66.
+ moduli = list(filter((lambda x: bits+x[1] <= 66), moduli)) + moduli
+ multi_sqr = True
+ need_trans = True
+ if not moduli or moduli[0][2].change_ring(ZZ)(2) == 3 + 2**bits:
+ # For modulus 3, CLMUL_TRI is obviously better.
+ return None
+ elif style == CLMUL_TRI:
+ moduli = list(filter(lambda x: bits+x[1] <= 66, moduli)) + moduli
+ moduli = list(filter(lambda x: x[0] == 3, moduli))
+ multi_sqr = True
+ need_trans = True
+ else:
+ assert(False)
+ if not moduli:
+ return None
+ return moduli[0][2]
+
+def print_result(bits, style):
+ if style == INT:
+ multi_sqr = False
+ need_trans = False
+ table_id = "%i" % bits
+ elif style == MD:
+ pass
+ elif style == CLMUL:
+ multi_sqr = True
+ need_trans = True
+ table_id = "%i" % bits
+ elif style == CLMUL_TRI:
+ multi_sqr = True
+ need_trans = True
+ table_id = "TRI%i" % bits
+ else:
+ assert(False)
+
+ nmodulus = pick_modulus(bits, INT)
+ modulus = pick_modulus(bits, style)
+ if modulus is None:
+ return
+
+ if style == MD:
+ print("* *%s*" % print_modulus_md(modulus))
+ return
+
+ if bits > 32:
+ typ = "uint64_t"
+ elif bits > 16:
+ typ = "uint32_t"
+ elif bits > 8:
+ typ = "uint16_t"
+ else:
+ typ = "uint8_t"
+
+ ttyp = lintranstype(typ, bits, 4)
+ rtyp = lintranstype(typ, bits, 6)
+
+ F.<f> = GF(2**bits, modulus=modulus)
+
+ include_table = True
+ if style != INT and style != CLMUL:
+ cmodulus = pick_modulus(bits, CLMUL)
+ if cmodulus == modulus:
+ include_table = False
+ table_id = "%i" % bits
+
+ if include_table:
+ print("typedef %s StatTable%s;" % (rtyp, table_id))
+ rtyp = "StatTable%s" % table_id
+ if (style == INT):
+ print("typedef %s DynTable%s;" % (ttyp, table_id))
+ ttyp = "DynTable%s" % table_id
+
+ if need_trans:
+ if modulus != nmodulus:
+ # If the bitstream modulus is not the best modulus for
+ # this implementation a conversion table will be needed.
+ ctyp = rtyp
+ NF.<nf> = GF(2**bits, modulus=nmodulus)
+ ctables = conv_tables(NF, F, bits)
+ loadtbl = "&LOAD_TABLE_%s" % table_id
+ savetbl = "&SAVE_TABLE_%s" % table_id
+ if include_table:
+ print("constexpr %s LOAD_TABLE_%s({%s});" % (ctyp, table_id, ", ".join([fmt(x,typ) for x in ctables[0]])))
+ print("constexpr %s SAVE_TABLE_%s({%s});" % (ctyp, table_id, ", ".join([fmt(x,typ) for x in ctables[1]])))
+ else:
+ ctyp = "IdTrans"
+ loadtbl = "&ID_TRANS"
+ savetbl = "&ID_TRANS"
+ else:
+ assert(modulus == nmodulus)
+
+ if include_table:
+ print("constexpr %s SQR_TABLE_%s({%s});" % (rtyp, table_id, ", ".join([fmt(x,typ) for x in sqr_table(f, bits, 1)])))
+ if multi_sqr:
+ # Repeated squaring is a linearised polynomial so in F(2^n) it is
+ # F(2) linear and can be computed by a simple bit-matrix.
+ # Repeated squaring is especially useful in powering ladders such as
+ # for inversion.
+ # When certain repeated squaring tables are not in use, use the QRT
+ # table instead to make the C++ compiler happy (it always has the
+ # same type).
+ sqr2 = "&QRT_TABLE_%s" % table_id
+ sqr4 = "&QRT_TABLE_%s" % table_id
+ sqr8 = "&QRT_TABLE_%s" % table_id
+ sqr16 = "&QRT_TABLE_%s" % table_id
+ if ((bits - 1) >= 4):
+ if include_table:
+ print("constexpr %s SQR2_TABLE_%s({%s});" % (rtyp, table_id, ", ".join([fmt(x,typ) for x in sqr_table(f, bits, 2)])))
+ sqr2 = "&SQR2_TABLE_%s" % table_id
+ if ((bits - 1) >= 8):
+ if include_table:
+ print("constexpr %s SQR4_TABLE_%s({%s});" % (rtyp, table_id, ", ".join([fmt(x,typ) for x in sqr_table(f, bits, 4)])))
+ sqr4 = "&SQR4_TABLE_%s" % table_id
+ if ((bits - 1) >= 16):
+ if include_table:
+ print("constexpr %s SQR8_TABLE_%s({%s});" % (rtyp, table_id, ", ".join([fmt(x,typ) for x in sqr_table(f, bits, 8)])))
+ sqr8 = "&SQR8_TABLE_%s" % table_id
+ if ((bits - 1) >= 32):
+ if include_table:
+ print("constexpr %s SQR16_TABLE_%s({%s});" % (rtyp, table_id, ", ".join([fmt(x,typ) for x in sqr_table(f, bits, 16)])))
+ sqr16 = "&SQR16_TABLE_%s" % table_id
+ if include_table:
+ print("constexpr %s QRT_TABLE_%s({%s});" % (rtyp, table_id, ", ".join([fmt(x,typ) for x in qrt_table(F, f, bits)])))
+
+ modulus_weight = modulus.hamming_weight()
+ modulus_degree = (modulus - p**bits).degree()
+ modulus_int = (modulus - p**bits).change_ring(ZZ)(2)
+
+ lfsr = ""
+
+ if style == INT:
+ print("typedef Field<%s, %i, %i, %s, %s, &SQR_TABLE_%s, &QRT_TABLE_%s%s> Field%i;" % (typ, bits, modulus_int, rtyp, ttyp, table_id, table_id, lfsr, bits))
+ elif style == CLMUL:
+ print("typedef Field<%s, %i, %i, %s, &SQR_TABLE_%s, %s, %s, %s, %s, &QRT_TABLE_%s, %s, %s, %s%s> Field%i;" % (typ, bits, modulus_int, rtyp, table_id, sqr2, sqr4, sqr8, sqr16, table_id, ctyp, loadtbl, savetbl, lfsr, bits))
+ elif style == CLMUL_TRI:
+ print("typedef FieldTri<%s, %i, %i, %s, &SQR_TABLE_%s, %s, %s, %s, %s, &QRT_TABLE_%s, %s, %s, %s> FieldTri%i;" % (typ, bits, modulus_degree, rtyp, table_id, sqr2, sqr4, sqr8, sqr16, table_id, ctyp, loadtbl, savetbl, bits))
+ else:
+ assert(False)
+
+for bits in range(2, 65):
+ print("#ifdef ENABLE_FIELD_INT_%i" % bits)
+ print("// %i bit field" % bits)
+ print_result(bits, INT)
+ print("#endif")
+ print("")
+
+for bits in range(2, 65):
+ print("#ifdef ENABLE_FIELD_INT_%i" % bits)
+ print("// %i bit field" % bits)
+ print_result(bits, CLMUL)
+ print_result(bits, CLMUL_TRI)
+ print("#endif")
+ print("")
+
+for bits in range(2, 65):
+ print_result(bits, MD)
diff --git a/doc/log2_factorial.sage b/doc/log2_factorial.sage
new file mode 100644
index 00000000..afc6d66c
--- /dev/null
+++ b/doc/log2_factorial.sage
@@ -0,0 +1,85 @@
+import bisect
+
+INPUT_BITS = 32
+TABLE_BITS = 5
+INT_BITS = 64
+EXACT_FPBITS = 256
+
+F = RealField(100) # overkill
+
+def BestOverApproxInvLog2(mulof, maxd):
+ """
+ Compute denominator of an approximation of 1/log(2).
+
+ Specifically, find the value of d (<= maxd, and a multiple of mulof)
+ such that ceil(d/log(2))/d is the best approximation of 1/log(2).
+ """
+ dist=1
+ best=0
+ # Precomputed denominators that lead to good approximations of 1/log(2)
+ for d in [1, 2, 9, 70, 131, 192, 445, 1588, 4319, 11369, 18419, 25469, 287209, 836158, 3057423, 8336111, 21950910, 35565709, 49180508, 161156323, 273132138, 385107953, 882191721]:
+ kd = lcm(mulof, d)
+ if kd <= maxd:
+ n = ceil(kd / log(2))
+ dis = F((n / kd) - 1 / log(2))
+ if dis < dist:
+ dist = dis
+ best = kd
+ return best
+
+
+LOG2_TABLE = []
+A = 0
+B = 0
+C = 0
+D = 0
+K = 0
+
+def Setup(k):
+ global LOG2_TABLE, A, B, C, D, K
+ K = k
+ LOG2_TABLE = []
+ for i in range(2 ** TABLE_BITS):
+ LOG2_TABLE.append(int(floor(F(K * log(1 + i / 2**TABLE_BITS, 2)))))
+
+ # Maximum for (2*x+1)*LogK2(x)
+ max_T = (2^(INPUT_BITS + 1) - 1) * (INPUT_BITS*K - 1)
+ # Maximum for A
+ max_A = (2^INT_BITS - 1) // max_T
+ D = BestOverApproxInvLog2(2 * K, max_A * 2 * K)
+ A = D // (2 * K)
+ B = int(ceil(F(D/log(2))))
+ C = int(floor(F(D*log(2*pi,2)/2)))
+
+def LogK2(n):
+ assert(n >= 1 and n < (1 << INPUT_BITS))
+ bits = Integer(n).nbits()
+ return K * (bits - 1) + LOG2_TABLE[((n << (INPUT_BITS - bits)) >> (INPUT_BITS - TABLE_BITS - 1)) - 2**TABLE_BITS]
+
+def Log2Fact(n):
+ # Use formula (A*(2*x+1)*LogK2(x) - B*x + C) / D
+ return (A*(2*n+1)*LogK2(n) - B*n + C) // D + (n < 3)
+
+RES = [int(F(log(factorial(i),2))) for i in range(EXACT_FPBITS * 10)]
+
+best_worst_ratio = 0
+
+for K in range(1, 10000):
+ Setup(K)
+ assert(LogK2(1) == 0)
+ assert(LogK2(2) == K)
+ assert(LogK2(4) == 2 * K)
+ good = True
+ worst_ratio = 1
+ for i in range(1, EXACT_FPBITS * 10):
+ exact = RES[i]
+ approx = Log2Fact(i)
+ if not (approx <= exact and ((approx == exact) or (approx >= EXACT_FPBITS and exact >= EXACT_FPBITS))):
+ good = False
+ break
+ if worst_ratio * exact > approx:
+ worst_ratio = approx / exact
+ if good and worst_ratio > best_worst_ratio:
+ best_worst_ratio = worst_ratio
+ print("Formula: (%i*(2*x+1)*floor(%i*log2(x)) - %i*x + %i) / %i; log(max_ratio)=%f" % (A, K, B, C, D, RR(-log(worst_ratio))))
+ print("LOG2K_TABLE: %r" % LOG2_TABLE)
diff --git a/doc/math.md b/doc/math.md
new file mode 100644
index 00000000..04ce801c
--- /dev/null
+++ b/doc/math.md
@@ -0,0 +1,117 @@
+# The mathematics of Minisketch sketches
+
+This is an unconventional mathematical overview of the PinSketch algorithm without references to coding theory<sup>[[1]](#myfootnote1)</sup>.
+
+## Set sketches
+
+A sketch, for the purpose of this description, can be seen as a "set checksum" with two peculiar properties:
+
+* Sketches have a predetermined capacity, and when the number of elements in the set is not higher than the capacity, minisketch will always recover the entire set from the sketch. A sketch of *b*-bit elements with capacity *c* can be stored in *bc* bits.
+* The sketches of two sets can be combined by adding them (XOR) to obtain a sketch of the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) between the two sets (*i.e.*, all elements that occur in one but not both input sets).
+
+This overview explains how sets can be converted into a sketch and how a set can be recovered from a sketch.
+
+## From field elements to sketches
+
+**Data entries as field elements**
+
+Every integer in the range *[1...2<sup>b</sup>-1]* (the acceptable data elements for a Minisketch sketch with field size *b*) can be mapped to a nonzero field element of *GF(2<sup>b</sup>)*. In this [finite field](https://en.wikipedia.org/wiki/Finite_field), we can add and multiply elements together, with many of the expected properties for those operations. Addition (and subtraction!) of field elements corresponds to bitwise XOR of the integers they correspond to, though multiplication is more involved.
+
+**Sets as power series**
+
+We define a function *S* which maps field elements *m* to the following [formal power series](https://en.wikipedia.org/wiki/Formal_power_series) (similar to a polynomial, except there can be an infinite number of terms, and we don't care about concepts like convergence as we're never going to actually evaluate it for a specific value of *x*):
+
+* *S(m) = 1 + mx + m<sup>2</sup>x<sup>2</sup> + m<sup>3</sup>x<sup>3</sup> + ...*.
+
+We then extend this function to operate on sets of field elements, by adding together the images of every set element. If *M = {m<sub>1</sub>, m<sub>2</sub>, ... }*:
+
+* *S(M) = S({m<sub>1</sub>,m<sub>2</sub>,...}) = S(m<sub>1</sub>) + S(m<sub>2</sub>) + ... = (1 + 1 + ...) + (m<sub>1</sub> + m<sub>2</sub> + ...)x + (m<sub>1</sub><sup>2</sup> + m<sub>2</sub><sup>2</sup> + ...)x<sup>2</sup> + (m<sub>1</sub><sup>3</sup> + ...*
+
+Because in our field addition corresponds to XOR of integers, it holds for every *a* that *a + a = 0*. This carries over to the *S* function, meaning that *S(a) + S(a) = 0* for every *a*. This means that the coefficients of these power series have the second of the properties we
+desire from a sketch, namely that an efficient operation exists to
+combine two sketches such that the result is a sketch of the symmetric
+difference of the sets. It holds that
+*S({m<sub>1</sub>,m<sub>2</sub>}) + S({m<sub>2</sub>,m<sub>3</sub>}) = S(m<sub>1</sub>) + (S(m<sub>2</sub>) + S(m<sub>2</sub>)) + S(m<sub>3</sub>) = S(m<sub>1</sub>) + S(m<sub>3</sub>) = S({m<sub>1</sub>,m<sub>3</sub>})*. The question is whether we can also efficiently recover the elements from their power series' coefficients.
+
+**An infinity of coefficients is hard**
+
+To make reasoning about these power series easier, notice that the series for a single element is in fact a [geometric series](https://en.wikipedia.org/wiki/Geometric_series). If we were working over real numbers rather than a finite field and *|mx| < 1*, it would converge to *(1 - mx)<sup>-1</sup>*. Convergence has no meaning in formal power series, however it is still the case that:
+
+* *(1 - mx) S(m) = 1*
+
+You can verify this by seeing that every coefficient except the constant one gets cancelled out by the multiplication. This can be generalized to the series for multiple set elements. For two elements we have:
+
+* *(1 - m<sub>1</sub>x) (1 - m<sub>2</sub>x) S({m<sub>1</sub>,m<sub>2</sub>}) = (1 - m<sub>1</sub>x) (1 - m<sub>2</sub>x) (S(m<sub>1</sub>) + S(m<sub>2</sub>)) = (1 - m<sub>2</sub>x) + (1 - m<sub>1</sub>x)*
+
+And for three:
+
+* *(1 - m<sub>1</sub>x) (1 - m<sub>2</sub>x) (1 - m<sub>3</sub>x) S({m<sub>1</sub>,m<sub>2</sub>,m<sub>3</sub>}) = (1 - m<sub>1</sub>x) (1 - m<sub>2</sub>x) (1 - m<sub>3</sub>x) (S(m<sub>1</sub>) + S(m<sub>2</sub>) + S(m<sub>3</sub>)) = (1 - m<sub>2</sub>x)(1 - m<sub>3</sub>x) + (1 - m<sub>1</sub>x)(1 - m<sub>3</sub>x) + (1 - m<sub>1</sub>x)(1 - m<sub>2</sub>x)*
+
+In each case, we notice that multiplying *S(M)* with *(1 - m<sub>i</sub>x)* for each element *m<sub>i</sub> ∈ M* results in a polynomial of degree *n-1*.
+
+**Solving for the set elements**
+
+The above insight lets us build a solver that extracts the set elements from the coefficients of a power series. If we can find a polynomial *L* that is the product of *n* different *(1 - m<sub>i</sub>x)* factors for various values of *m<sub>i</sub>*, such that *P = S(M)L* is an *n-1* degree polynomial, then those values *m<sub>i</sub>* are the elements of *M*.
+
+The coefficients of *P* are nontrivial expressions of the set elements themselves. However, we can just focus on the coefficients of degree *n* and higher in *P*, as those are all 0. Let *s<sub>i</sub>* be the coefficients of *S(M)*, and *l<sub>i</sub>* the coefficients of L. In other words, *S(M) = s<sub>0</sub> + s<sub>1</sub>x + s<sub>2</sub>x<sup>2</sup> + s<sub>3</sub>x<sup>3</sup> + ...* and *L = l<sub>0</sub> + l<sub>1</sub>x + l<sub>2</sub>x<sup>2</sup> + l<sub>3</sub>x<sup>3</sup> + ... + l<sub>n</sub>x<sup>n</sup>*. Note that *l<sub>0</sub> = 1*, as it is the product of all the *1* terms in the *(1 - m<sub>i</sub>x)* factors.
+
+Here are the equations for the coefficients of *S(M)L* of degree *n+1* through *2n*:
+* *s<sub>n+1</sub> + s<sub>n+0</sub>l<sub>1</sub> + s<sub>n-1</sub>l<sub>2</sub> + s<sub>n-2</sub>l<sub>3</sub> + ... + s<sub>1</sub>l<sub>n</sub> = 0*
+* *s<sub>n+2</sub> + s<sub>n+1</sub>l<sub>1</sub> + s<sub>n+0</sub>l<sub>2</sub> + s<sub>n-1</sub>l<sub>3</sub> + ... + s<sub>2</sub>l<sub>n</sub> = 0*
+* *s<sub>n+3</sub> + s<sub>n+2</sub>l<sub>1</sub> + s<sub>n+1</sub>l<sub>2</sub> + s<sub>n+0</sub>l<sub>3</sub> + ... + s<sub>3</sub>l<sub>n</sub> = 0*
+* ...
+* *s<sub>2n</sub> + s<sub>2n-1</sub>l<sub>1</sub> + s<sub>2n-2</sub>l<sub>2</sub> + s<sub>2n-3</sub>l<sub>3</sub> + ... + s<sub>n</sub>l<sub>n</sub> = 0*
+
+These are *n* linear equations with *n* unknowns (the *l<sub>i<sub>*
+values, for *i=1..n*), which can be solved using [Gaussian elimination](https://en.wikipedia.org/wiki/Gaussian_elimination). After doing so,
+we have the coefficients of *L*, which can then be [factored](https://en.wikipedia.org/wiki/Factorization_of_polynomials_over_finite_fields)
+into first degree factors of the form *(1 - m<sub>i</sub>x)*. The resulting *m* values are our set elements.
+
+**Putting it all together**
+
+Interestingly, only *2n* coefficients of *S(M)* were needed for solving
+the set of equations above. This means we have our answer: the
+coefficients *1* through *2n* of *S(M)*, or the list
+*[m<sub>1</sub> + m<sub>2</sub> + ..., m<sub>1</sub><sup>2</sup> + m<sub>2</sub><sup>2</sup> + ..., ..., m<sub>1</sub><sup>2n</sup> + m<sub>2</sub><sup>2n</sup> + ...]*
+functions as a sketch, satisfying the two properties we want:
+
+* Sketches can be combined to form the sketch of their symmetric difference, by simply pairwise adding the list elements together.
+* With *2n* list elements we can efficiently recover *n* elements from a sketch.
+
+**Capacity and difference**
+
+The approach above only works when the number of elements *n* in the sketch is known. Of course we want to support cases where only an upper bound on the number of elements in the sketch is known, the capacity *c*. Given that we can reconstruct a set of size *c* from a sketch with *2c* terms, we should be able to reconstruct a set of size *n* too as long as *n ≤ c*. This is simply a matter of trying to solve the above set of equations assuming values of *n* that count down from *c* until a solution is found for one. This is known as the [Peterson-Gorenstein-Zierler algorithm](https://en.wikipedia.org/wiki/BCH_code#Peterson%E2%80%93Gorenstein%E2%80%93Zierler_algorithm).
+
+## Optimizations
+
+**Halving the sketch size**
+
+We can in fact only include the odd terms in the sketch, and reconstruct the even ones before solving the equation to find *L*. This means the size of a sketch becomes just *c* field elements, the same size as would be needed to send its contents naively.
+
+To see how this is possible, we need the [Frobenius endomorphism](https://en.wikipedia.org/wiki/Frobenius_endomorphism), which in short states that in fields where *x + x = 0* it holds that *(x + y)<sup>2</sup> = x<sup>2</sup> + y<sup>2</sup>* for every *x* and *y* (the dream of every high school math student!). This means that:
+
+* *s<sub>2</sub> = m<sub>1</sub><sup>2</sup> + m<sub>2</sub><sup>2</sup> + ... = (m<sub>1</sub> + m<sub>2</sub> + ...)<sup>2</sup> = s<sub>1</sub><sup>2</sup>*.
+* *s<sub>4</sub> = m<sub>1</sub><sup>4</sup> + m<sub>2</sub><sup>4</sup> + ... = (m<sub>1</sub><sup>2</sup> + m<sub>2</sub><sup>2</sup> + ...)<sup>2</sup> = s<sub>2</sub><sup>2</sup>*.
+* *s<sub>6</sub> = m<sub>1</sub><sup>6</sup> + m<sub>2</sub><sup>6</sup> + ... = (m<sub>1</sub><sup>3</sup> + m<sub>2</sub><sup>3</sup> + ...)<sup>2</sup> = s<sub>3</sub><sup>2</sup>*.
+* ...
+
+In other words, we only need to send *s<sub>1</sub>, s<sub>3</sub>, s<sub>5</sub>, ..., s<sub>2n-1</sub>* to recover all *2n* *s<sub>i</sub>* values, and proceed with reconstruction.
+
+**Quadratic performance rather than cubic**
+
+Using Gaussian elimination to solve the set of equations above for the *l<sub>i</sub>* values requires *O(n<sup>3</sup>)* field operations. However, due to the special structure in the equations (look at the repeated *s<sub>i</sub>* values), it can be solved in *O(n<sup>2</sup>)* time using a number of techniques, including the [Berlekamp-Massey algorithm](https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm) (BM).
+
+**Roots instead of factorization**
+
+As explained above, the polynomial *L* can be factored into *(1 - m<sub>i</sub>x)* factors, where the values *m<sub>i</sub>* are the set elements. However, since we know that a decodable sketch must result in a polynomial that is fully factorizable into degree-*1* factors, we can instead use a more efficient root-finding algorithm rather than a factorization algorithm. As the root of each *(1 - m<sub>i</sub>x)* factor is *m<sub>i</sub><sup>-1</sup>*, we conclude that the set elements are in fact the inverses of the roots of *L*.
+
+**Avoiding inversions**
+
+As inversions are a relatively expensive operation, it would be useful to avoid them.
+
+Say that we're trying to find the inverses of the roots of *L = 1 + l<sub>1</sub>x + l<sub>2</sub>x<sup>2</sup> + ... + l<sub>n</sub>x<sup>n</sup>*, then we're really interested in the solutions *y* for *1 + l<sub>1</sub>y<sup>-1</sup> + l<sub>2</sub>y<sup>-2</sup> + ... + l<sub>n</sub>y<sup>-n</sup> = 0*. By multiplying both sides in the equations with *y<sup>n</sup>*, we find *l<sub>n</sub> + l<sub>n-1</sub>y + l<sub>n-2</sub>y<sup>2</sup> + ... + y<sup>n</sup> = 0*.
+
+In other words, we can find the inverses of the roots of *L* by instead factoring the polynomial with the coefficients of *L* in reverse order.
+
+* <a name="myfootnote1">[1]</a> For those familiar with coding theory: PinSketch communicates a set difference by encoding the set members as errors in a binary [BCH](https://en.wikipedia.org/wiki/BCH_code) codeword 2<sup>bits</sup> in size and sends the syndromes.
+ The linearity of the syndromes provides all the properties needed for a sketch. Sketch decoding is simply finding the error locations. Decode is much faster than an ordinary BCH decoder for such a large codeword because the need to take a discrete log is avoided by storing the set in the roots directly instead of in an exponent (logically permuting the bits of the codeword).
diff --git a/doc/minisketch-vs.png b/doc/minisketch-vs.png
new file mode 100644
index 00000000..aed810de
Binary files /dev/null and b/doc/minisketch-vs.png differ
diff --git a/doc/moduli.md b/doc/moduli.md
new file mode 100644
index 00000000..379ac481
--- /dev/null
+++ b/doc/moduli.md
@@ -0,0 +1,65 @@
+These are the irreducible polynomials over *GF(2)* used to represent field elements:
+
+* *x<sup>2</sup> + x + 1*
+* *x<sup>3</sup> + x + 1*
+* *x<sup>4</sup> + x + 1*
+* *x<sup>5</sup> + x<sup>2</sup> + 1*
+* *x<sup>6</sup> + x + 1*
+* *x<sup>7</sup> + x + 1*
+* *x<sup>8</sup> + x<sup>4</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>9</sup> + x + 1*
+* *x<sup>10</sup> + x<sup>3</sup> + 1*
+* *x<sup>11</sup> + x<sup>2</sup> + 1*
+* *x<sup>12</sup> + x<sup>3</sup> + 1*
+* *x<sup>13</sup> + x<sup>4</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>14</sup> + x<sup>5</sup> + 1*
+* *x<sup>15</sup> + x + 1*
+* *x<sup>16</sup> + x<sup>5</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>17</sup> + x<sup>3</sup> + 1*
+* *x<sup>18</sup> + x<sup>3</sup> + 1*
+* *x<sup>19</sup> + x<sup>5</sup> + x<sup>2</sup> + x + 1*
+* *x<sup>20</sup> + x<sup>3</sup> + 1*
+* *x<sup>21</sup> + x<sup>2</sup> + 1*
+* *x<sup>22</sup> + x + 1*
+* *x<sup>23</sup> + x<sup>5</sup> + 1*
+* *x<sup>24</sup> + x<sup>4</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>25</sup> + x<sup>3</sup> + 1*
+* *x<sup>26</sup> + x<sup>4</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>27</sup> + x<sup>5</sup> + x<sup>2</sup> + x + 1*
+* *x<sup>28</sup> + x + 1*
+* *x<sup>29</sup> + x<sup>2</sup> + 1*
+* *x<sup>30</sup> + x + 1*
+* *x<sup>31</sup> + x<sup>3</sup> + 1*
+* *x<sup>32</sup> + x<sup>7</sup> + x<sup>3</sup> + x<sup>2</sup> + 1*
+* *x<sup>33</sup> + x<sup>10</sup> + 1*
+* *x<sup>34</sup> + x<sup>7</sup> + 1*
+* *x<sup>35</sup> + x<sup>2</sup> + 1*
+* *x<sup>36</sup> + x<sup>9</sup> + 1*
+* *x<sup>37</sup> + x<sup>6</sup> + x<sup>4</sup> + x + 1*
+* *x<sup>38</sup> + x<sup>6</sup> + x<sup>5</sup> + x + 1*
+* *x<sup>39</sup> + x<sup>4</sup> + 1*
+* *x<sup>40</sup> + x<sup>5</sup> + x<sup>4</sup> + x<sup>3</sup> + 1*
+* *x<sup>41</sup> + x<sup>3</sup> + 1*
+* *x<sup>42</sup> + x<sup>7</sup> + 1*
+* *x<sup>43</sup> + x<sup>6</sup> + x<sup>4</sup> + x<sup>3</sup> + 1*
+* *x<sup>44</sup> + x<sup>5</sup> + 1*
+* *x<sup>45</sup> + x<sup>4</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>46</sup> + x + 1*
+* *x<sup>47</sup> + x<sup>5</sup> + 1*
+* *x<sup>48</sup> + x<sup>5</sup> + x<sup>3</sup> + x<sup>2</sup> + 1*
+* *x<sup>49</sup> + x<sup>9</sup> + 1*
+* *x<sup>50</sup> + x<sup>4</sup> + x<sup>3</sup> + x<sup>2</sup> + 1*
+* *x<sup>51</sup> + x<sup>6</sup> + x<sup>3</sup> + x + 1*
+* *x<sup>52</sup> + x<sup>3</sup> + 1*
+* *x<sup>53</sup> + x<sup>6</sup> + x<sup>2</sup> + x + 1*
+* *x<sup>54</sup> + x<sup>9</sup> + 1*
+* *x<sup>55</sup> + x<sup>7</sup> + 1*
+* *x<sup>56</sup> + x<sup>7</sup> + x<sup>4</sup> + x<sup>2</sup> + 1*
+* *x<sup>57</sup> + x<sup>4</sup> + 1*
+* *x<sup>58</sup> + x<sup>19</sup> + 1*
+* *x<sup>59</sup> + x<sup>7</sup> + x<sup>4</sup> + x<sup>2</sup> + 1*
+* *x<sup>60</sup> + x + 1*
+* *x<sup>61</sup> + x<sup>5</sup> + x<sup>2</sup> + x + 1*
+* *x<sup>62</sup> + x<sup>29</sup> + 1*
+* *x<sup>63</sup> + x + 1*
+* *x<sup>64</sup> + x<sup>4</sup> + x<sup>3</sup> + x + 1*
diff --git a/doc/plot_bits.png b/doc/plot_bits.png
new file mode 100644
index 00000000..6e907d6b
Binary files /dev/null and b/doc/plot_bits.png differ
diff --git a/doc/plot_capacity.png b/doc/plot_capacity.png
new file mode 100644
index 00000000..b4f760da
Binary files /dev/null and b/doc/plot_capacity.png differ
diff --git a/doc/plot_diff.png b/doc/plot_diff.png
new file mode 100644
index 00000000..08ab6a86
Binary files /dev/null and b/doc/plot_diff.png differ
diff --git a/doc/plot_size.png b/doc/plot_size.png
new file mode 100644
index 00000000..b2192177
Binary files /dev/null and b/doc/plot_size.png differ
diff --git a/doc/protocoltips.md b/doc/protocoltips.md
new file mode 100644
index 00000000..610407eb
--- /dev/null
+++ b/doc/protocoltips.md
@@ -0,0 +1,30 @@
+# Tips for designing protocols using `libminisketch`
+
+Sending a sketch is less efficient than just sending your whole set with efficient entropy coding if the number of differences is larger than *log<sub>2</sub>( 2<sup>b</sup> choose set_size ) / b*.
+
+In most applications your set can be hashed to entries just large enough to make the probability of collision negligible. This can be a considerable speedup and bandwidth savings. Short hashes (<128 bits) should be salted with an unpredictable value to prevent malicious inputs from intentionally causing collisions. Salting also allows an entry missed due to a collision to be reconciled on a later run with a different salt. Pre-hashing may not be possible in some applications, such as where there is only one-way communication, where the confidentiality of entry origin matters, or where security depends on the total absence of collisions.
+
+Some element sizes are faster to decode than others; see the benchmarks in the readme.
+
+Almost all the computational burden of reconciliation is in minisketch_decode(). Denial-of-service attacks can be mitigated by arranging protocol flow so that a party requests a sketch and decodes it rather than a construction where the participants will decode unsolicited sketches. Decode times can be constrained by limiting sketch capacity or via the max_count argument to minisketch_decode().
+
+In most cases you don't actually know the size of the set difference in advance, but often you know a lower bound on it (the difference in set sizes).
+
+* There are difference size estimation techniques such as min-wise hashing<sup>[[1]](#myfootnote1)</sup> or random projections<sup>[[2]](#myfootnote2)</sup>, but complex estimators can end up using more bandwidth than they save.
+
+* It may be useful to always overestimate the sketch size needed to amortize communications overheads (*e.g.* packet headers, round trip delays).
+
+* If the total data sent would end up leaving you better off having just sent the whole set, per above, then you can send the set in response to a failure but leave out as many elements as the size of the previously sent sketch. The receiver can decode the partial set and use the data they already have to complete it, reducing bandwidth waste.
+
+* Additional elements can be sent for a sketch as few as one at a time with little decode cost until enough data is received to decode. This is most easily implemented by always computing the largest sketch size and sending it incrementally as needed.
+
+* Because sketches are linear you can adaptively subdivide to decode an overfull set. The sender uses a hash function to select approximately half their set members and sends a sketch of those members. The receiver can do the same and combine the result with the initially sent sketch to get two sketches with roughly half the number of members and attempt to decode them. Repeat recursively on failure. This adaptive subdivision procedure makes decode time essentially linear at the cost of communications inefficiency. Minisketches can also be used as the cells in an IBLT for similar reasons.
+
+Less efficient reconciliation techniques like IBLT or adaptive subdivision, or overheads like complex estimators effectively lower the threshold where sending the whole set efficiently would use less bandwidth.
+
+When the number of differences is more than 2<sup>b/2-1</sup> an alternative sketch encoding is possible that is somewhat smaller, but requires a table of size 2<sup>b</sup>; contact the authors if you have an application where that might be useful.
+
+## References
+
+* <a name="myfootnote1">[1]</a> Broder, A. *On the Resemblance and Containment of Documents* Proceedings of the Compression and Complexity of Sequences 1997 [[PDF]](https://www.cs.princeton.edu/courses/archive/spring13/cos598C/broder97resemblance.pdf)
+* <a name="myfootnote2">[2]</a> Feigenbaum, Joan and Kannan, Sampath and Strauss, Martin J. and Viswanathan, Mahesh. *An Approximate L1-Difference Algorithm for Massive Data Streams* SIAM J. Comput. 2003 [[PDF]](http://www.cs.yale.edu/homes/jf/FKSV1.pdf)
diff --git a/include/minisketch.h b/include/minisketch.h
new file mode 100644
index 00000000..f222f233
--- /dev/null
+++ b/include/minisketch.h
@@ -0,0 +1,368 @@
+#ifndef _MINISKETCH_H_
+#define _MINISKETCH_H_ 1
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+# include <BaseTsd.h>
+ typedef SSIZE_T ssize_t;
+#else
+# include <unistd.h>
+#endif
+
+#ifndef MINISKETCH_API
+# if defined(_WIN32)
+# ifdef MINISKETCH_BUILD
+# define MINISKETCH_API __declspec(dllexport)
+# else
+# define MINISKETCH_API
+# endif
+# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(MINISKETCH_BUILD)
+# define MINISKETCH_API __attribute__ ((visibility ("default")))
+# else
+# define MINISKETCH_API
+# endif
+#endif
+
+#ifdef __cplusplus
+# if __cplusplus >= 201103L
+# include <memory>
+# include <vector>
+# include <cassert>
+# if __cplusplus >= 201703L
+# include <optional>
+# endif // __cplusplus >= 201703L
+# endif // __cplusplus >= 201103L
+extern "C" {
+#endif // __cplusplus
+
+/** Opaque type for decoded sketches. */
+typedef struct minisketch minisketch;
+
+/** Determine whether support for elements of `bits` bits was compiled in. */
+MINISKETCH_API int minisketch_bits_supported(uint32_t bits);
+
+/** Determine the maximum number of implementations available.
+ *
+ * Multiple implementations may be available for a given element size, with
+ * different performance characteristics on different hardware.
+ *
+ * Each implementation is identified by a number from 0 to the output of this
+ * function call, inclusive. Note that not every combination of implementation
+ * and element size may exist (see further).
+*/
+MINISKETCH_API uint32_t minisketch_implementation_max(void);
+
+/** Determine if the a combination of bits and implementation number is available.
+ *
+ * Returns 1 if it is, 0 otherwise.
+ */
+MINISKETCH_API int minisketch_implementation_supported(uint32_t bits, uint32_t implementation);
+
+/** Construct a sketch for a given element size, implementation and capacity.
+ *
+ * If the combination of `bits` and `implementation` is unavailable, or when
+ * OOM occurs, NULL is returned. If minisketch_implementation_supported
+ * returns 1 for the specified bits and implementation, this will always succeed
+ * (except when allocation fails).
+ *
+ * If the result is not NULL, it must be destroyed using minisketch_destroy.
+ */
+MINISKETCH_API minisketch* minisketch_create(uint32_t bits, uint32_t implementation, size_t capacity);
+
+/** Get the element size of a sketch in bits. */
+MINISKETCH_API uint32_t minisketch_bits(const minisketch* sketch);
+
+/** Get the capacity of a sketch. */
+MINISKETCH_API size_t minisketch_capacity(const minisketch* sketch);
+
+/** Get the implementation of a sketch. */
+MINISKETCH_API uint32_t minisketch_implementation(const minisketch* sketch);
+
+/** Set the seed for randomizing algorithm choices to a fixed value.
+ *
+ * By default, sketches are initialized with a random seed. This is important
+ * to avoid scenarios where an attacker could force worst-case behavior.
+ *
+ * This function initializes the seed to a user-provided value (any 64-bit
+ * integer is acceptable, regardless of field size).
+ *
+ * When seed is -1, a fixed internal value with predictable behavior is
+ * used. It is only intended for testing.
+ */
+MINISKETCH_API void minisketch_set_seed(minisketch* sketch, uint64_t seed);
+
+/** Clone a sketch.
+ *
+ * The result must be destroyed using minisketch_destroy.
+ */
+MINISKETCH_API minisketch* minisketch_clone(const minisketch* sketch);
+
+/** Destroy a sketch.
+ *
+ * The pointer that was passed in may not be used anymore afterwards.
+ */
+MINISKETCH_API void minisketch_destroy(minisketch* sketch);
+
+/** Compute the size in bytes for serializing a given sketch. */
+MINISKETCH_API size_t minisketch_serialized_size(const minisketch* sketch);
+
+/** Serialize a sketch to bytes. */
+MINISKETCH_API void minisketch_serialize(const minisketch* sketch, unsigned char* output);
+
+/** Deserialize a sketch from bytes. */
+MINISKETCH_API void minisketch_deserialize(minisketch* sketch, const unsigned char* input);
+
+/** Add an element to a sketch.
+ *
+ * If the element to be added is too large for the sketch, the most significant
+ * bits of the element are dropped. More precisely, if the element size of
+ * `sketch` is b bits, then this function adds the unsigned integer represented
+ * by the b least significant bits of `element` to `sketch`.
+ *
+ * If the element to be added is 0 (after potentially dropping the most significant
+ * bits), then this function is a no-op. Sketches cannot contain an element with
+ * the value 0.
+ *
+ * Note that adding the same element a second time removes it again.
+ */
+MINISKETCH_API void minisketch_add_uint64(minisketch* sketch, uint64_t element);
+
+/** Merge the elements of another sketch into this sketch.
+ *
+ * After merging, `sketch` will contain every element that existed in one but not
+ * both of the input sketches. It can be seen as an exclusive or operation on
+ * the set elements. If the capacity of `other_sketch` is lower than `sketch`'s,
+ * merging reduces the capacity of `sketch` to that of `other_sketch`.
+ *
+ * This function returns the capacity of `sketch` after merging has been performed
+ * (where this capacity is at least 1), or 0 to indicate that merging has failed because
+ * the two input sketches differ in their element size or implementation. If 0 is
+ * returned, `sketch` (and its capacity) have not been modified.
+ *
+ * It is also possible to perform this operation directly on the serializations
+ * of two sketches with the same element size and capacity by performing a bitwise XOR
+ * of the serializations.
+ */
+MINISKETCH_API size_t minisketch_merge(minisketch* sketch, const minisketch* other_sketch);
+
+/** Decode a sketch.
+ *
+ * `output` is a pointer to an array of `max_element` uint64_t's, which will be
+ * filled with the elements in this sketch.
+ *
+ * The return value is the number of decoded elements, or -1 if decoding failed.
+ */
+MINISKETCH_API ssize_t minisketch_decode(const minisketch* sketch, size_t max_elements, uint64_t* output);
+
+/** Compute the capacity needed to achieve a certain rate of false positives.
+ *
+ * A sketch with capacity c and no more than c elements can always be decoded
+ * correctly. However, if it has more than c elements, or contains just random
+ * bytes, it is possible that it will still decode, but the result will be
+ * nonsense. This can be counteracted by increasing the capacity slightly.
+ *
+ * Given a field size bits, an intended number of elements that can be decoded
+ * max_elements, and a false positive probability of 1 in 2**fpbits, this
+ * function computes the necessary capacity. It is only guaranteed to be
+ * accurate up to fpbits=256.
+ */
+MINISKETCH_API size_t minisketch_compute_capacity(uint32_t bits, size_t max_elements, uint32_t fpbits);
+
+/** Compute what max_elements can be decoded for a certain rate of false positives.
+ *
+ * This is the inverse operation of minisketch_compute_capacity. It determines,
+ * given a field size bits, a capacity of a sketch, and an acceptable false
+ * positive probability of 1 in 2**fpbits, what the maximum allowed
+ * max_elements value is. If no value of max_elements would give the desired
+ * false positive probability, 0 is returned.
+ *
+ * Note that this is not an exact inverse of minisketch_compute_capacity. For
+ * example, with bits=32, fpbits=16, and max_elements=8,
+ * minisketch_compute_capacity will return 9, as capacity 8 would only have a
+ * false positive chance of 1 in 2^15.3. Increasing the capacity to 9 however
+ * decreases the fp chance to 1 in 2^47.3, enough for max_elements=9 (with fp
+ * chance of 1 in 2^18.5). Therefore, minisketch_compute_max_elements with
+ * capacity=9 will return 9.
+ */
+MINISKETCH_API size_t minisketch_compute_max_elements(uint32_t bits, size_t capacity, uint32_t fpbits);
+
+#ifdef __cplusplus
+}
+
+#if __cplusplus >= 201103L
+/** Simple RAII C++11 wrapper around the minisketch API. */
+class Minisketch
+{
+ struct Deleter
+ {
+ void operator()(minisketch* ptr) const
+ {
+ minisketch_destroy(ptr);
+ }
+ };
+
+ std::unique_ptr<minisketch, Deleter> m_minisketch;
+
+public:
+ /** Check whether the library supports fields of the given size. */
+ static bool BitsSupported(uint32_t bits) noexcept { return minisketch_bits_supported(bits); }
+
+ /** Get the highest supported implementation number. */
+ static uint32_t MaxImplementation() noexcept { return minisketch_implementation_max(); }
+
+ /** Check whether the library supports fields with a given size and implementation number.
+ * If a particular field size `bits` is supported, implementation 0 is always supported for it.
+ * Higher implementation numbers may or may not be available as well, up to MaxImplementation().
+ */
+ static bool ImplementationSupported(uint32_t bits, uint32_t implementation) noexcept { return minisketch_implementation_supported(bits, implementation); }
+
+ /** Given field size and a maximum number of decodable elements n, compute what capacity c to
+ * use so that sketches with more elements than n have a chance no higher than 2^-fpbits of
+ * being decoded incorrectly (and will instead fail when decoding for up to n elements).
+ *
+ * See minisketch_compute_capacity for more details. */
+ static size_t ComputeCapacity(uint32_t bits, size_t max_elements, uint32_t fpbits) noexcept { return minisketch_compute_capacity(bits, max_elements, fpbits); }
+
+ /** Reverse operation of ComputeCapacity. See minisketch_compute_max_elements. */
+ static size_t ComputeMaxElements(uint32_t bits, size_t capacity, uint32_t fpbits) noexcept { return minisketch_compute_max_elements(bits, capacity, fpbits); }
+
+ /** Construct a clone of the specified sketch. */
+ Minisketch(const Minisketch& sketch) noexcept
+ {
+ if (sketch.m_minisketch) {
+ m_minisketch = std::unique_ptr<minisketch, Deleter>(minisketch_clone(sketch.m_minisketch.get()));
+ }
+ }
+
+ /** Make this Minisketch a clone of the specified one. */
+ Minisketch& operator=(const Minisketch& sketch) noexcept
+ {
+ if (this != &sketch && sketch.m_minisketch) {
+ m_minisketch = std::unique_ptr<minisketch, Deleter>(minisketch_clone(sketch.m_minisketch.get()));
+ }
+ return *this;
+ }
+
+ /** Check whether this Minisketch object is valid. */
+ explicit operator bool() const noexcept { return bool{m_minisketch}; }
+
+ /** Default constructor is deleted. */
+ Minisketch() noexcept = delete;
+
+ /** Move constructor. */
+ Minisketch(Minisketch&&) noexcept = default;
+
+ /** Move assignment. */
+ Minisketch& operator=(Minisketch&&) noexcept = default;
+
+ /** Construct a Minisketch object with the specified parameters.
+ *
+ * If bits is not BitsSupported(), or the combination of bits and capacity is not
+ * ImplementationSupported(), or OOM occurs internally, an invalid Minisketch
+ * object will be constructed. Use operator bool() to check that this isn't the
+ * case before performing any other operations. */
+ Minisketch(uint32_t bits, uint32_t implementation, size_t capacity) noexcept
+ {
+ m_minisketch = std::unique_ptr<minisketch, Deleter>(minisketch_create(bits, implementation, capacity));
+ }
+
+ /** Create a Minisketch object sufficiently large for the specified number of elements at given fpbits.
+ * It may construct an invalid object, which you may need to check for. */
+ static Minisketch CreateFP(uint32_t bits, uint32_t implementation, size_t max_elements, uint32_t fpbits) noexcept
+ {
+ return Minisketch(bits, implementation, ComputeCapacity(bits, max_elements, fpbits));
+ }
+
+ /** Return the field size for a (valid) Minisketch object. */
+ uint32_t GetBits() const noexcept { return minisketch_bits(m_minisketch.get()); }
+
+ /** Return the capacity for a (valid) Minisketch object. */
+ size_t GetCapacity() const noexcept { return minisketch_capacity(m_minisketch.get()); }
+
+ /** Return the implementation number for a (valid) Minisketch object. */
+ uint32_t GetImplementation() const noexcept { return minisketch_implementation(m_minisketch.get()); }
+
+ /** Set the seed for a (valid) Minisketch object. See minisketch_set_seed(). */
+ Minisketch& SetSeed(uint64_t seed) noexcept
+ {
+ minisketch_set_seed(m_minisketch.get(), seed);
+ return *this;
+ }
+
+ /** Add (or remove, if already present) an element to a (valid) Minisketch object.
+ * See minisketch_add_uint64(). */
+ Minisketch& Add(uint64_t element) noexcept
+ {
+ minisketch_add_uint64(m_minisketch.get(), element);
+ return *this;
+ }
+
+ /** Merge sketch into *this; both have to be valid Minisketch objects.
+ * See minisketch_merge for details. */
+ Minisketch& Merge(const Minisketch& sketch) noexcept
+ {
+ minisketch_merge(m_minisketch.get(), sketch.m_minisketch.get());
+ return *this;
+ }
+
+ /** Decode this (valid) Minisketch object into the result vector, up to as many elements as the
+ * vector's size permits. */
+ bool Decode(std::vector<uint64_t>& result) const
+ {
+ ssize_t ret = minisketch_decode(m_minisketch.get(), result.size(), result.data());
+ if (ret == -1) return false;
+ result.resize(ret);
+ return true;
+ }
+
+ /** Get the serialized size in bytes for this (valid) Minisketch object.. */
+ size_t GetSerializedSize() const noexcept { return minisketch_serialized_size(m_minisketch.get()); }
+
+ /** Serialize this (valid) Minisketch object as a byte vector. */
+ std::vector<unsigned char> Serialize() const
+ {
+ std::vector<unsigned char> result(GetSerializedSize());
+ minisketch_serialize(m_minisketch.get(), result.data());
+ return result;
+ }
+
+ /** Deserialize into this (valid) Minisketch from an object containing its bytes (which has data()
+ * and size() members). */
+ template<typename T>
+ Minisketch& Deserialize(
+ const T& obj,
+ typename std::enable_if<
+ std::is_convertible<typename std::remove_pointer<decltype(obj.data())>::type (*)[], const unsigned char (*)[]>::value &&
+ std::is_convertible<decltype(obj.size()), std::size_t>::value,
+ std::nullptr_t
+ >::type = nullptr) noexcept
+ {
+ assert(GetSerializedSize() == obj.size());
+ minisketch_deserialize(m_minisketch.get(), obj.data());
+ return *this;
+ }
+
+#if __cplusplus >= 201703L
+ /** C++17 only: like Decode(), but up to a specified number of elements into an optional vector. */
+ std::optional<std::vector<uint64_t>> Decode(size_t max_elements) const
+ {
+ std::vector<uint64_t> result(max_elements);
+ ssize_t ret = minisketch_decode(m_minisketch.get(), max_elements, result.data());
+ if (ret == -1) return {};
+ result.resize(ret);
+ return result;
+ }
+
+ /** C++17 only: similar to Decode(), but with specified false positive probability. */
+ std::optional<std::vector<uint64_t>> DecodeFP(uint32_t fpbits) const
+ {
+ return Decode(ComputeMaxElements(GetBits(), GetCapacity(), fpbits));
+ }
+#endif // __cplusplus >= 201703L
+};
+#endif // __cplusplus >= 201103L
+#endif // __cplusplus
+
+#endif // _MINISKETCH_H_
diff --git a/sources.mk b/sources.mk
new file mode 100644
index 00000000..386a4fcc
--- /dev/null
+++ b/sources.mk
@@ -0,0 +1,58 @@
+# - All variables are namespaced with MINISKETCH_ to avoid colliding with
+# downstream makefiles.
+# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the
+# _INT postfix is applied.
+# - Convenience variables, for example a MINISKETCH_FIELDS_DIR should not be used
+# as they interfere with automatic dependency generation
+# - The %reldir% is the relative path from the Makefile.am. This allows
+# downstreams to use these variables without having to manually account for
+# the path change.
+
+MINISKETCH_INCLUDE_DIR_INT = %reldir%/include
+
+MINISKETCH_DIST_HEADERS_INT =
+MINISKETCH_DIST_HEADERS_INT += %reldir%/include/minisketch.h
+
+MINISKETCH_LIB_HEADERS_INT =
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/false_positives.h
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/fielddefines.h
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/int_utils.h
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/lintrans.h
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/sketch.h
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/sketch_impl.h
+MINISKETCH_LIB_HEADERS_INT += %reldir%/src/util.h
+
+MINISKETCH_LIB_SOURCES_INT =
+MINISKETCH_LIB_SOURCES_INT += %reldir%/src/minisketch.cpp
+
+MINISKETCH_FIELD_GENERIC_HEADERS_INT =
+MINISKETCH_FIELD_GENERIC_HEADERS_INT += %reldir%/src/fields/generic_common_impl.h
+
+MINISKETCH_FIELD_GENERIC_SOURCES_INT =
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_1byte.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_2bytes.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_3bytes.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_4bytes.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_5bytes.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_6bytes.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_7bytes.cpp
+MINISKETCH_FIELD_GENERIC_SOURCES_INT += %reldir%/src/fields/generic_8bytes.cpp
+
+MINISKETCH_FIELD_CLMUL_HEADERS_INT =
+MINISKETCH_FIELD_CLMUL_HEADERS_INT += %reldir%/src/fields/clmul_common_impl.h
+
+MINISKETCH_FIELD_CLMUL_SOURCES_INT =
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_1byte.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_2bytes.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_3bytes.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_4bytes.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_5bytes.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_6bytes.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_7bytes.cpp
+MINISKETCH_FIELD_CLMUL_SOURCES_INT += %reldir%/src/fields/clmul_8bytes.cpp
+
+MINISKETCH_BENCH_SOURCES_INT =
+MINISKETCH_BENCH_SOURCES_INT += %reldir%/src/bench.cpp
+
+MINISKETCH_TEST_SOURCES_INT =
+MINISKETCH_TEST_SOURCES_INT += %reldir%/src/test.cpp
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 00000000..76250c7b
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,76 @@
+add_library(minisketch_field_sources INTERFACE)
+target_sources(minisketch_field_sources
+ INTERFACE
+ fields/generic_1byte.cpp
+ fields/generic_2bytes.cpp
+ fields/generic_3bytes.cpp
+ fields/generic_4bytes.cpp
+ fields/generic_5bytes.cpp
+ fields/generic_6bytes.cpp
+ fields/generic_7bytes.cpp
+ fields/generic_8bytes.cpp
+)
+if(HAVE_CLMUL)
+ set(clmul_sources
+ fields/clmul_1byte.cpp
+ fields/clmul_2bytes.cpp
+ fields/clmul_3bytes.cpp
+ fields/clmul_4bytes.cpp
+ fields/clmul_5bytes.cpp
+ fields/clmul_6bytes.cpp
+ fields/clmul_7bytes.cpp
+ fields/clmul_8bytes.cpp
+ )
+ set_property(SOURCE minisketch.cpp
+ PROPERTY COMPILE_DEFINITIONS HAVE_CLMUL
+ )
+ set_property(SOURCE ${clmul_sources}
+ PROPERTY COMPILE_OPTIONS ${CLMUL_CXXFLAGS}
+ )
+ target_sources(minisketch_field_sources INTERFACE ${clmul_sources})
+endif()
+
+add_compile_definitions($<$<BOOL:${HAVE_CLZ}>:HAVE_CLZ>)
+
+add_library(minisketch minisketch.cpp)
+set_property(TARGET minisketch PROPERTY PUBLIC_HEADER
+ ${PROJECT_SOURCE_DIR}/include/minisketch.h
+)
+target_include_directories(minisketch
+ INTERFACE
+ $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
+)
+target_link_libraries(minisketch PRIVATE minisketch_field_sources)
+
+add_library(minisketch_verify EXCLUDE_FROM_ALL minisketch.cpp)
+target_compile_definitions(minisketch_verify
+ PUBLIC
+ MINISKETCH_VERIFY
+)
+target_link_libraries(minisketch_verify PRIVATE minisketch_field_sources)
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ target_compile_options(minisketch_verify
+ PRIVATE
+ /wd4702
+ )
+endif()
+
+if(MINISKETCH_BUILD_TESTS)
+ add_executable(test-noverify test.cpp)
+ target_link_libraries(test-noverify PRIVATE minisketch)
+ add_test(NAME ${PROJECT_NAME}_test_noverify COMMAND test-noverify)
+
+ add_executable(test-verify test.cpp)
+ target_link_libraries(test-verify PRIVATE minisketch_verify)
+ add_test(NAME ${PROJECT_NAME}_test_verify COMMAND test-verify)
+endif()
+
+if(MINISKETCH_BUILD_BENCHMARK)
+ add_executable(bench bench.cpp)
+ target_link_libraries(bench PRIVATE minisketch)
+endif()
+
+if(MINISKETCH_INSTALL)
+ include(GNUInstallDirs)
+ install(TARGETS minisketch)
+endif()
diff --git a/src/bench.cpp b/src/bench.cpp
new file mode 100644
index 00000000..dc44379f
--- /dev/null
+++ b/src/bench.cpp
@@ -0,0 +1,118 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include "../include/minisketch.h"
+#include <string.h>
+#include <memory>
+#include <vector>
+#include <chrono>
+#include <random>
+#include <set>
+#include <algorithm>
+
+int main(int argc, char** argv) {
+ if (argc < 1 || argc > 4) {
+ printf("Usage: %s [syndromes=150] [errors=syndromes] [iters=10]\n", argv[0]);
+ return 1;
+ }
+ int syndromes = argc > 1 ? strtoul(argv[1], NULL, 10) : 150;
+ int errors = argc > 2 ? strtoul(argv[2], NULL, 10) : syndromes;
+ int iters = argc > 3 ? strtoul(argv[3], NULL, 10) : 10;
+ if (syndromes < 0 || syndromes > 1000000) {
+ printf("Number of syndromes (%i) out of range 0..1000000\n", syndromes);
+ return 1;
+ }
+ if (errors < 0) {
+ printf("Number of errors (%i) is negative(%i)\n", errors, syndromes);
+ return 1;
+ }
+ if (iters < 0 || iters > 1000000000) {
+ printf("Number of iterations (%i) out of range 0..1000000000\n", iters);
+ return 1;
+ }
+ uint32_t max_impl = minisketch_implementation_max();
+ for (int bits = 2; bits <= 64; ++bits) {
+ if (errors > pow(2.0, bits - 1)) continue;
+ if (!minisketch_bits_supported(bits)) continue;
+ printf("recover[ms]\t% 3i\t", bits);
+ for (uint32_t impl = 0; impl <= max_impl; ++impl) {
+ std::vector<minisketch*> states;
+ std::vector<uint64_t> roots(2 * syndromes);
+ std::random_device rng;
+ std::uniform_int_distribution<uint64_t> dist(1, (uint64_t(1) << bits) - 1);
+ states.resize(iters);
+ std::vector<double> benches;
+ benches.reserve(iters);
+ for (int i = 0; i < iters; ++i) {
+ states[i] = minisketch_create(bits, impl, syndromes);
+ if (!states[i]) break;
+ std::set<uint64_t> done;
+ for (int j = 0; j < errors; ++j) {
+ uint64_t r;
+ do {
+ r = dist(rng);
+ } while (done.count(r));
+ done.insert(r);
+ minisketch_add_uint64(states[i], r);
+ }
+ }
+ if (!states[0]) {
+ printf(" -\t");
+ } else {
+ for (auto& state : states) {
+ auto start = std::chrono::steady_clock::now();
+ minisketch_decode(state, 2 * syndromes, roots.data());
+ auto stop = std::chrono::steady_clock::now();
+ std::chrono::duration<double> dur(stop - start);
+ benches.push_back(dur.count());
+ }
+ std::sort(benches.begin(), benches.end());
+ printf("% 10.5f\t", benches[0] * 1000.0);
+ }
+ for (auto& state : states) {
+ minisketch_destroy(state);
+ }
+ }
+ printf("\n");
+ printf("create[ns]\t% 3i\t", bits);
+ for (uint32_t impl = 0; impl <= max_impl; ++impl) {
+ std::vector<minisketch*> states;
+ std::random_device rng;
+ std::uniform_int_distribution<uint64_t> dist;
+ std::vector<uint64_t> data;
+ data.resize(errors * 10);
+ states.resize(iters);
+ std::vector<double> benches;
+ benches.reserve(iters);
+ for (int i = 0; i < iters; ++i) {
+ states[i] = minisketch_create(bits, impl, syndromes);
+ }
+ for (size_t i = 0; i < data.size(); ++i) {
+ data[i] = dist(rng);
+ }
+ if (!states[0]) {
+ printf(" -\t");
+ } else {
+ for (auto& state : states) {
+ auto start = std::chrono::steady_clock::now();
+ for (auto val : data) {
+ minisketch_add_uint64(state, val);
+ }
+ auto stop = std::chrono::steady_clock::now();
+ std::chrono::duration<double> dur(stop - start);
+ benches.push_back(dur.count());
+ }
+ std::sort(benches.begin(), benches.end());
+ printf("% 10.5f\t", benches[0] * 1000000000.0 / data.size() / syndromes);
+ }
+ for (auto& state : states) {
+ minisketch_destroy(state);
+ }
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/src/false_positives.h b/src/false_positives.h
new file mode 100644
index 00000000..9d035899
--- /dev/null
+++ b/src/false_positives.h
@@ -0,0 +1,112 @@
+/**********************************************************************
+ * Copyright (c) 2020 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _MINISKETCH_FALSE_POSITIVES_H_
+#define _MINISKETCH_FALSE_POSITIVES_H_
+
+#include "util.h"
+
+#include "int_utils.h"
+
+#include <stdint.h>
+
+namespace {
+
+/** Compute floor(log2(x!)), exactly up to x=57; an underestimate up to x=2^32-1. */
+uint64_t Log2Factorial(uint32_t x) {
+ //! Values of floor(106*log2(1 + i/32)) for i=0..31
+ static constexpr uint8_t T[32] = {
+ 0, 4, 9, 13, 18, 22, 26, 30, 34, 37, 41, 45, 48, 52, 55, 58, 62, 65, 68,
+ 71, 74, 77, 80, 82, 85, 88, 90, 93, 96, 98, 101, 103
+ };
+ int bits = CountBits(x, 32);
+ // Compute an (under)estimate of floor(106*log2(x)).
+ // This works by relying on floor(log2(x)) = countbits(x)-1, and adding
+ // precision using the top 6 bits of x (the highest one of which is always
+ // one).
+ unsigned l2_106 = 106 * (bits - 1) + T[((x << (32 - bits)) >> 26) & 31];
+ // Based on Stirling approximation for log2(x!):
+ // log2(x!) = log(x!) / log(2)
+ // = ((x + 1/2) * log(x) - x + log(2*pi)/2 + ...) / log(2)
+ // = (x + 1/2) * log2(x) - x/log(2) + log2(2*pi)/2 + ...
+ // = 1/2*(2*x+1)*log2(x) - (1/log(2))*x + log2(2*pi)/2 + ...
+ // = 1/212*(2*x+1)*(106*log2(x)) + (-1/log(2))*x + log2(2*pi)/2 + ...
+ // where 418079/88632748 is exactly 1/212
+ // -127870026/88632748 is slightly less than -1/log(2)
+ // 117504694/88632748 is less than log2(2*pi)/2
+ // A correction term is only needed for x < 3.
+ //
+ // See doc/log2_factorial.sage for how these constants were obtained.
+ return (418079 * (2 * uint64_t{x} + 1) * l2_106 - 127870026 * uint64_t{x} + 117504694 + 88632748 * (x < 3)) / 88632748;
+}
+
+/** Compute floor(log2(2^(bits * capacity) / sum((2^bits - 1) choose k, k=0..capacity))), for bits>1
+ *
+ * See doc/gen_basefpbits.sage for how the tables were obtained. */
+uint64_t BaseFPBits(uint32_t bits, uint32_t capacity) {
+ // Correction table for low bits/capacities
+ static constexpr uint8_t ADD5[] = {1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12};
+ static constexpr uint8_t ADD6[] = {1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 10, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 24, 24, 24, 24};
+ static constexpr uint8_t ADD7[] = {1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 7, 8, 9, 9, 9, 10, 11, 11, 12, 12, 13, 13, 15, 15, 15, 16, 17, 17, 18, 19, 20, 20};
+ static constexpr uint8_t ADD8[] = {1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 9, 9};
+ static constexpr uint8_t ADD9[] = {1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 3, 3, 3, 3, 4, 3, 3, 4, 4, 4, 4};
+
+ if (capacity == 0) return 0;
+ uint64_t ret = 0;
+ if (bits < 32 && capacity >= (1U << bits)) {
+ ret = uint64_t{bits} * (capacity - (1U << bits) + 1);
+ capacity = (1U << bits) - 1;
+ }
+ ret += Log2Factorial(capacity);
+ switch (bits) {
+ case 2: return ret + (capacity <= 2 ? 0 : 1);
+ case 3: return ret + (capacity <= 2 ? 0 : (0x2a5 >> 2 * (capacity - 3)) & 3);
+ case 4: return ret + (capacity <= 3 ? 0 : (0xb6d91a449 >> 3 * (capacity - 4)) & 7);
+ case 5: return ret + (capacity <= 4 ? 0 : ADD5[capacity - 5]);
+ case 6: return ret + (capacity <= 4 ? 0 : capacity > 54 ? 25 : ADD6[capacity - 5]);
+ case 7: return ret + (capacity <= 4 ? 0 : capacity > 57 ? 21 : ADD7[capacity - 5]);
+ case 8: return ret + (capacity <= 9 ? 0 : capacity > 56 ? 10 : ADD8[capacity - 10]);
+ case 9: return ret + (capacity <= 11 ? 0 : capacity > 54 ? 5 : ADD9[capacity - 12]);
+ case 10: return ret + (capacity <= 21 ? 0 : capacity > 50 ? 2 : (0x1a6665545555041 >> 2 * (capacity - 22)) & 3);
+ case 11: return ret + (capacity <= 21 ? 0 : capacity > 45 ? 1 : (0x5b3dc1 >> (capacity - 22)) & 1);
+ case 12: return ret + (capacity <= 21 ? 0 : capacity > 57 ? 0 : (0xe65522041 >> (capacity - 22)) & 1);
+ case 13: return ret + (capacity <= 27 ? 0 : capacity > 55 ? 0 : (0x8904081 >> (capacity - 28)) & 1);
+ case 14: return ret + (capacity <= 47 ? 0 : capacity > 48 ? 0 : 1);
+ default: return ret;
+ }
+}
+
+size_t ComputeCapacity(uint32_t bits, size_t max_elements, uint32_t fpbits) {
+ if (bits == 0) return 0;
+ if (max_elements > 0xffffffff) return max_elements;
+ uint64_t base_fpbits = BaseFPBits(bits, static_cast<uint32_t>(max_elements));
+ // The fpbits provided by the base max_elements==capacity case are sufficient.
+ if (base_fpbits >= fpbits) return max_elements;
+ // Otherwise, increment capacity by ceil(fpbits / bits) beyond that.
+ return max_elements + (fpbits - base_fpbits + bits - 1) / bits;
+}
+
+size_t ComputeMaxElements(uint32_t bits, size_t capacity, uint32_t fpbits) {
+ if (bits == 0) return 0;
+ if (capacity > 0xffffffff) return capacity;
+ // Start with max_elements=capacity, and decrease max_elements until the corresponding capacity is capacity.
+ size_t max_elements = capacity;
+ while (true) {
+ size_t capacity_for_max_elements = ComputeCapacity(bits, max_elements, fpbits);
+ CHECK_SAFE(capacity_for_max_elements >= capacity);
+ if (capacity_for_max_elements <= capacity) return max_elements;
+ size_t adjust = capacity_for_max_elements - capacity;
+ // Decrementing max_elements by N will at most decrement the corresponding capacity by N.
+ // As the observed capacity is adjust too high, we can safely decrease max_elements by adjust.
+ // If that brings us into negative max_elements territory, no solution exists and we return 0.
+ if (max_elements < adjust) return 0;
+ max_elements -= adjust;
+ }
+}
+
+} // namespace
+
+#endif
diff --git a/src/fielddefines.h b/src/fielddefines.h
new file mode 100644
index 00000000..510cb81f
--- /dev/null
+++ b/src/fielddefines.h
@@ -0,0 +1,560 @@
+/**********************************************************************
+ * Copyright (c) 2021 Cory Fields *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _MINISKETCH_FIELDDEFINES_H_
+#define _MINISKETCH_FIELDDEFINES_H_
+
+/*
+
+This file translates external defines ENABLE_FIELD_FOO, DISABLE_FIELD_FOO, and
+DISABLE_DEFAULT_FIELDS to internal ones: ENABLE_FIELD_INT_FOO. Only the
+resulting internal includes should be used.
+
+Default: All fields enabled
+-DDISABLE_FIELD_3: All fields except 3 are enabled
+-DENABLE_FIELD_3: All fields enabled
+-DDISABLE_DEFAULT_FIELDS: Error, no fields enabled
+-DDISABLE_DEFAULT_FIELDS -DENABLE_FIELD_3: Only field 3 enabled
+-DDISABLE_DEFAULT_FIELDS -DENABLE_FIELD_2 -DENABLE_FIELD_3: Only fields 2 and 3 are enabled
+-DDISABLE_DEFAULT_FIELDS -DENABLE_FIELD_2 -DENABLE_FIELD_3 -DDISABLE_FIELD_3: Only field 2 enabled
+
+*/
+
+#ifdef DISABLE_DEFAULT_FIELDS
+#if defined(ENABLE_FIELD_2) && !defined(DISABLE_FIELD_2)
+#define ENABLE_FIELD_INT_2
+#endif
+#if defined(ENABLE_FIELD_3) && !defined(DISABLE_FIELD_3)
+#define ENABLE_FIELD_INT_3
+#endif
+#if defined(ENABLE_FIELD_4) && !defined(DISABLE_FIELD_4)
+#define ENABLE_FIELD_INT_4
+#endif
+#if defined(ENABLE_FIELD_5) && !defined(DISABLE_FIELD_5)
+#define ENABLE_FIELD_INT_5
+#endif
+#if defined(ENABLE_FIELD_6) && !defined(DISABLE_FIELD_6)
+#define ENABLE_FIELD_INT_6
+#endif
+#if defined(ENABLE_FIELD_7) && !defined(DISABLE_FIELD_7)
+#define ENABLE_FIELD_INT_7
+#endif
+#if defined(ENABLE_FIELD_8) && !defined(DISABLE_FIELD_8)
+#define ENABLE_FIELD_INT_8
+#endif
+#if defined(ENABLE_FIELD_9) && !defined(DISABLE_FIELD_9)
+#define ENABLE_FIELD_INT_9
+#endif
+#if defined(ENABLE_FIELD_10) && !defined(DISABLE_FIELD_10)
+#define ENABLE_FIELD_INT_10
+#endif
+#if defined(ENABLE_FIELD_11) && !defined(DISABLE_FIELD_11)
+#define ENABLE_FIELD_INT_11
+#endif
+#if defined(ENABLE_FIELD_12) && !defined(DISABLE_FIELD_12)
+#define ENABLE_FIELD_INT_12
+#endif
+#if defined(ENABLE_FIELD_13) && !defined(DISABLE_FIELD_13)
+#define ENABLE_FIELD_INT_13
+#endif
+#if defined(ENABLE_FIELD_14) && !defined(DISABLE_FIELD_14)
+#define ENABLE_FIELD_INT_14
+#endif
+#if defined(ENABLE_FIELD_15) && !defined(DISABLE_FIELD_15)
+#define ENABLE_FIELD_INT_15
+#endif
+#if defined(ENABLE_FIELD_16) && !defined(DISABLE_FIELD_16)
+#define ENABLE_FIELD_INT_16
+#endif
+#if defined(ENABLE_FIELD_17) && !defined(DISABLE_FIELD_17)
+#define ENABLE_FIELD_INT_17
+#endif
+#if defined(ENABLE_FIELD_18) && !defined(DISABLE_FIELD_18)
+#define ENABLE_FIELD_INT_18
+#endif
+#if defined(ENABLE_FIELD_19) && !defined(DISABLE_FIELD_19)
+#define ENABLE_FIELD_INT_19
+#endif
+#if defined(ENABLE_FIELD_20) && !defined(DISABLE_FIELD_20)
+#define ENABLE_FIELD_INT_20
+#endif
+#if defined(ENABLE_FIELD_21) && !defined(DISABLE_FIELD_21)
+#define ENABLE_FIELD_INT_21
+#endif
+#if defined(ENABLE_FIELD_22) && !defined(DISABLE_FIELD_22)
+#define ENABLE_FIELD_INT_22
+#endif
+#if defined(ENABLE_FIELD_23) && !defined(DISABLE_FIELD_23)
+#define ENABLE_FIELD_INT_23
+#endif
+#if defined(ENABLE_FIELD_24) && !defined(DISABLE_FIELD_24)
+#define ENABLE_FIELD_INT_24
+#endif
+#if defined(ENABLE_FIELD_25) && !defined(DISABLE_FIELD_25)
+#define ENABLE_FIELD_INT_25
+#endif
+#if defined(ENABLE_FIELD_26) && !defined(DISABLE_FIELD_26)
+#define ENABLE_FIELD_INT_26
+#endif
+#if defined(ENABLE_FIELD_27) && !defined(DISABLE_FIELD_27)
+#define ENABLE_FIELD_INT_27
+#endif
+#if defined(ENABLE_FIELD_28) && !defined(DISABLE_FIELD_28)
+#define ENABLE_FIELD_INT_28
+#endif
+#if defined(ENABLE_FIELD_29) && !defined(DISABLE_FIELD_29)
+#define ENABLE_FIELD_INT_29
+#endif
+#if defined(ENABLE_FIELD_30) && !defined(DISABLE_FIELD_30)
+#define ENABLE_FIELD_INT_30
+#endif
+#if defined(ENABLE_FIELD_31) && !defined(DISABLE_FIELD_31)
+#define ENABLE_FIELD_INT_31
+#endif
+#if defined(ENABLE_FIELD_32) && !defined(DISABLE_FIELD_32)
+#define ENABLE_FIELD_INT_32
+#endif
+#if defined(ENABLE_FIELD_33) && !defined(DISABLE_FIELD_33)
+#define ENABLE_FIELD_INT_33
+#endif
+#if defined(ENABLE_FIELD_34) && !defined(DISABLE_FIELD_34)
+#define ENABLE_FIELD_INT_34
+#endif
+#if defined(ENABLE_FIELD_35) && !defined(DISABLE_FIELD_35)
+#define ENABLE_FIELD_INT_35
+#endif
+#if defined(ENABLE_FIELD_36) && !defined(DISABLE_FIELD_36)
+#define ENABLE_FIELD_INT_36
+#endif
+#if defined(ENABLE_FIELD_37) && !defined(DISABLE_FIELD_37)
+#define ENABLE_FIELD_INT_37
+#endif
+#if defined(ENABLE_FIELD_38) && !defined(DISABLE_FIELD_38)
+#define ENABLE_FIELD_INT_38
+#endif
+#if defined(ENABLE_FIELD_39) && !defined(DISABLE_FIELD_39)
+#define ENABLE_FIELD_INT_39
+#endif
+#if defined(ENABLE_FIELD_40) && !defined(DISABLE_FIELD_40)
+#define ENABLE_FIELD_INT_40
+#endif
+#if defined(ENABLE_FIELD_41) && !defined(DISABLE_FIELD_41)
+#define ENABLE_FIELD_INT_41
+#endif
+#if defined(ENABLE_FIELD_42) && !defined(DISABLE_FIELD_42)
+#define ENABLE_FIELD_INT_42
+#endif
+#if defined(ENABLE_FIELD_43) && !defined(DISABLE_FIELD_43)
+#define ENABLE_FIELD_INT_43
+#endif
+#if defined(ENABLE_FIELD_44) && !defined(DISABLE_FIELD_44)
+#define ENABLE_FIELD_INT_44
+#endif
+#if defined(ENABLE_FIELD_45) && !defined(DISABLE_FIELD_45)
+#define ENABLE_FIELD_INT_45
+#endif
+#if defined(ENABLE_FIELD_46) && !defined(DISABLE_FIELD_46)
+#define ENABLE_FIELD_INT_46
+#endif
+#if defined(ENABLE_FIELD_47) && !defined(DISABLE_FIELD_47)
+#define ENABLE_FIELD_INT_47
+#endif
+#if defined(ENABLE_FIELD_48) && !defined(DISABLE_FIELD_48)
+#define ENABLE_FIELD_INT_48
+#endif
+#if defined(ENABLE_FIELD_49) && !defined(DISABLE_FIELD_49)
+#define ENABLE_FIELD_INT_49
+#endif
+#if defined(ENABLE_FIELD_50) && !defined(DISABLE_FIELD_50)
+#define ENABLE_FIELD_INT_50
+#endif
+#if defined(ENABLE_FIELD_51) && !defined(DISABLE_FIELD_51)
+#define ENABLE_FIELD_INT_51
+#endif
+#if defined(ENABLE_FIELD_52) && !defined(DISABLE_FIELD_52)
+#define ENABLE_FIELD_INT_52
+#endif
+#if defined(ENABLE_FIELD_53) && !defined(DISABLE_FIELD_53)
+#define ENABLE_FIELD_INT_53
+#endif
+#if defined(ENABLE_FIELD_54) && !defined(DISABLE_FIELD_54)
+#define ENABLE_FIELD_INT_54
+#endif
+#if defined(ENABLE_FIELD_55) && !defined(DISABLE_FIELD_55)
+#define ENABLE_FIELD_INT_55
+#endif
+#if defined(ENABLE_FIELD_56) && !defined(DISABLE_FIELD_56)
+#define ENABLE_FIELD_INT_56
+#endif
+#if defined(ENABLE_FIELD_57) && !defined(DISABLE_FIELD_57)
+#define ENABLE_FIELD_INT_57
+#endif
+#if defined(ENABLE_FIELD_58) && !defined(DISABLE_FIELD_58)
+#define ENABLE_FIELD_INT_58
+#endif
+#if defined(ENABLE_FIELD_59) && !defined(DISABLE_FIELD_59)
+#define ENABLE_FIELD_INT_59
+#endif
+#if defined(ENABLE_FIELD_60) && !defined(DISABLE_FIELD_60)
+#define ENABLE_FIELD_INT_60
+#endif
+#if defined(ENABLE_FIELD_61) && !defined(DISABLE_FIELD_61)
+#define ENABLE_FIELD_INT_61
+#endif
+#if defined(ENABLE_FIELD_62) && !defined(DISABLE_FIELD_62)
+#define ENABLE_FIELD_INT_62
+#endif
+#if defined(ENABLE_FIELD_63) && !defined(DISABLE_FIELD_63)
+#define ENABLE_FIELD_INT_63
+#endif
+#if defined(ENABLE_FIELD_64) && !defined(DISABLE_FIELD_64)
+#define ENABLE_FIELD_INT_64
+#endif
+#else
+#if !defined(DISABLE_FIELD_2)
+#define ENABLE_FIELD_INT_2
+#endif
+#if !defined(DISABLE_FIELD_3)
+#define ENABLE_FIELD_INT_3
+#endif
+#if !defined(DISABLE_FIELD_4)
+#define ENABLE_FIELD_INT_4
+#endif
+#if !defined(DISABLE_FIELD_5)
+#define ENABLE_FIELD_INT_5
+#endif
+#if !defined(DISABLE_FIELD_6)
+#define ENABLE_FIELD_INT_6
+#endif
+#if !defined(DISABLE_FIELD_7)
+#define ENABLE_FIELD_INT_7
+#endif
+#if !defined(DISABLE_FIELD_8)
+#define ENABLE_FIELD_INT_8
+#endif
+#if !defined(DISABLE_FIELD_9)
+#define ENABLE_FIELD_INT_9
+#endif
+#if !defined(DISABLE_FIELD_10)
+#define ENABLE_FIELD_INT_10
+#endif
+#if !defined(DISABLE_FIELD_11)
+#define ENABLE_FIELD_INT_11
+#endif
+#if !defined(DISABLE_FIELD_12)
+#define ENABLE_FIELD_INT_12
+#endif
+#if !defined(DISABLE_FIELD_13)
+#define ENABLE_FIELD_INT_13
+#endif
+#if !defined(DISABLE_FIELD_14)
+#define ENABLE_FIELD_INT_14
+#endif
+#if !defined(DISABLE_FIELD_15)
+#define ENABLE_FIELD_INT_15
+#endif
+#if !defined(DISABLE_FIELD_16)
+#define ENABLE_FIELD_INT_16
+#endif
+#if !defined(DISABLE_FIELD_17)
+#define ENABLE_FIELD_INT_17
+#endif
+#if !defined(DISABLE_FIELD_18)
+#define ENABLE_FIELD_INT_18
+#endif
+#if !defined(DISABLE_FIELD_19)
+#define ENABLE_FIELD_INT_19
+#endif
+#if !defined(DISABLE_FIELD_20)
+#define ENABLE_FIELD_INT_20
+#endif
+#if !defined(DISABLE_FIELD_21)
+#define ENABLE_FIELD_INT_21
+#endif
+#if !defined(DISABLE_FIELD_22)
+#define ENABLE_FIELD_INT_22
+#endif
+#if !defined(DISABLE_FIELD_23)
+#define ENABLE_FIELD_INT_23
+#endif
+#if !defined(DISABLE_FIELD_24)
+#define ENABLE_FIELD_INT_24
+#endif
+#if !defined(DISABLE_FIELD_25)
+#define ENABLE_FIELD_INT_25
+#endif
+#if !defined(DISABLE_FIELD_26)
+#define ENABLE_FIELD_INT_26
+#endif
+#if !defined(DISABLE_FIELD_27)
+#define ENABLE_FIELD_INT_27
+#endif
+#if !defined(DISABLE_FIELD_28)
+#define ENABLE_FIELD_INT_28
+#endif
+#if !defined(DISABLE_FIELD_29)
+#define ENABLE_FIELD_INT_29
+#endif
+#if !defined(DISABLE_FIELD_30)
+#define ENABLE_FIELD_INT_30
+#endif
+#if !defined(DISABLE_FIELD_31)
+#define ENABLE_FIELD_INT_31
+#endif
+#if !defined(DISABLE_FIELD_32)
+#define ENABLE_FIELD_INT_32
+#endif
+#if !defined(DISABLE_FIELD_33)
+#define ENABLE_FIELD_INT_33
+#endif
+#if !defined(DISABLE_FIELD_34)
+#define ENABLE_FIELD_INT_34
+#endif
+#if !defined(DISABLE_FIELD_35)
+#define ENABLE_FIELD_INT_35
+#endif
+#if !defined(DISABLE_FIELD_36)
+#define ENABLE_FIELD_INT_36
+#endif
+#if !defined(DISABLE_FIELD_37)
+#define ENABLE_FIELD_INT_37
+#endif
+#if !defined(DISABLE_FIELD_38)
+#define ENABLE_FIELD_INT_38
+#endif
+#if !defined(DISABLE_FIELD_39)
+#define ENABLE_FIELD_INT_39
+#endif
+#if !defined(DISABLE_FIELD_40)
+#define ENABLE_FIELD_INT_40
+#endif
+#if !defined(DISABLE_FIELD_41)
+#define ENABLE_FIELD_INT_41
+#endif
+#if !defined(DISABLE_FIELD_42)
+#define ENABLE_FIELD_INT_42
+#endif
+#if !defined(DISABLE_FIELD_43)
+#define ENABLE_FIELD_INT_43
+#endif
+#if !defined(DISABLE_FIELD_44)
+#define ENABLE_FIELD_INT_44
+#endif
+#if !defined(DISABLE_FIELD_45)
+#define ENABLE_FIELD_INT_45
+#endif
+#if !defined(DISABLE_FIELD_46)
+#define ENABLE_FIELD_INT_46
+#endif
+#if !defined(DISABLE_FIELD_47)
+#define ENABLE_FIELD_INT_47
+#endif
+#if !defined(DISABLE_FIELD_48)
+#define ENABLE_FIELD_INT_48
+#endif
+#if !defined(DISABLE_FIELD_49)
+#define ENABLE_FIELD_INT_49
+#endif
+#if !defined(DISABLE_FIELD_50)
+#define ENABLE_FIELD_INT_50
+#endif
+#if !defined(DISABLE_FIELD_51)
+#define ENABLE_FIELD_INT_51
+#endif
+#if !defined(DISABLE_FIELD_52)
+#define ENABLE_FIELD_INT_52
+#endif
+#if !defined(DISABLE_FIELD_53)
+#define ENABLE_FIELD_INT_53
+#endif
+#if !defined(DISABLE_FIELD_54)
+#define ENABLE_FIELD_INT_54
+#endif
+#if !defined(DISABLE_FIELD_55)
+#define ENABLE_FIELD_INT_55
+#endif
+#if !defined(DISABLE_FIELD_56)
+#define ENABLE_FIELD_INT_56
+#endif
+#if !defined(DISABLE_FIELD_57)
+#define ENABLE_FIELD_INT_57
+#endif
+#if !defined(DISABLE_FIELD_58)
+#define ENABLE_FIELD_INT_58
+#endif
+#if !defined(DISABLE_FIELD_59)
+#define ENABLE_FIELD_INT_59
+#endif
+#if !defined(DISABLE_FIELD_60)
+#define ENABLE_FIELD_INT_60
+#endif
+#if !defined(DISABLE_FIELD_61)
+#define ENABLE_FIELD_INT_61
+#endif
+#if !defined(DISABLE_FIELD_62)
+#define ENABLE_FIELD_INT_62
+#endif
+#if !defined(DISABLE_FIELD_63)
+#define ENABLE_FIELD_INT_63
+#endif
+#if !defined(DISABLE_FIELD_64)
+#define ENABLE_FIELD_INT_64
+#endif
+#endif
+
+#if !defined(ENABLE_FIELD_INT_2) && \
+ !defined(ENABLE_FIELD_INT_3) && \
+ !defined(ENABLE_FIELD_INT_4) && \
+ !defined(ENABLE_FIELD_INT_5) && \
+ !defined(ENABLE_FIELD_INT_6) && \
+ !defined(ENABLE_FIELD_INT_7) && \
+ !defined(ENABLE_FIELD_INT_8) && \
+ !defined(ENABLE_FIELD_INT_9) && \
+ !defined(ENABLE_FIELD_INT_10) && \
+ !defined(ENABLE_FIELD_INT_11) && \
+ !defined(ENABLE_FIELD_INT_12) && \
+ !defined(ENABLE_FIELD_INT_13) && \
+ !defined(ENABLE_FIELD_INT_14) && \
+ !defined(ENABLE_FIELD_INT_15) && \
+ !defined(ENABLE_FIELD_INT_16) && \
+ !defined(ENABLE_FIELD_INT_17) && \
+ !defined(ENABLE_FIELD_INT_18) && \
+ !defined(ENABLE_FIELD_INT_19) && \
+ !defined(ENABLE_FIELD_INT_20) && \
+ !defined(ENABLE_FIELD_INT_21) && \
+ !defined(ENABLE_FIELD_INT_22) && \
+ !defined(ENABLE_FIELD_INT_23) && \
+ !defined(ENABLE_FIELD_INT_24) && \
+ !defined(ENABLE_FIELD_INT_25) && \
+ !defined(ENABLE_FIELD_INT_26) && \
+ !defined(ENABLE_FIELD_INT_27) && \
+ !defined(ENABLE_FIELD_INT_28) && \
+ !defined(ENABLE_FIELD_INT_29) && \
+ !defined(ENABLE_FIELD_INT_30) && \
+ !defined(ENABLE_FIELD_INT_31) && \
+ !defined(ENABLE_FIELD_INT_32) && \
+ !defined(ENABLE_FIELD_INT_33) && \
+ !defined(ENABLE_FIELD_INT_34) && \
+ !defined(ENABLE_FIELD_INT_35) && \
+ !defined(ENABLE_FIELD_INT_36) && \
+ !defined(ENABLE_FIELD_INT_37) && \
+ !defined(ENABLE_FIELD_INT_38) && \
+ !defined(ENABLE_FIELD_INT_39) && \
+ !defined(ENABLE_FIELD_INT_40) && \
+ !defined(ENABLE_FIELD_INT_41) && \
+ !defined(ENABLE_FIELD_INT_42) && \
+ !defined(ENABLE_FIELD_INT_43) && \
+ !defined(ENABLE_FIELD_INT_44) && \
+ !defined(ENABLE_FIELD_INT_45) && \
+ !defined(ENABLE_FIELD_INT_46) && \
+ !defined(ENABLE_FIELD_INT_47) && \
+ !defined(ENABLE_FIELD_INT_48) && \
+ !defined(ENABLE_FIELD_INT_49) && \
+ !defined(ENABLE_FIELD_INT_50) && \
+ !defined(ENABLE_FIELD_INT_51) && \
+ !defined(ENABLE_FIELD_INT_52) && \
+ !defined(ENABLE_FIELD_INT_53) && \
+ !defined(ENABLE_FIELD_INT_54) && \
+ !defined(ENABLE_FIELD_INT_55) && \
+ !defined(ENABLE_FIELD_INT_56) && \
+ !defined(ENABLE_FIELD_INT_57) && \
+ !defined(ENABLE_FIELD_INT_58) && \
+ !defined(ENABLE_FIELD_INT_59) && \
+ !defined(ENABLE_FIELD_INT_60) && \
+ !defined(ENABLE_FIELD_INT_61) && \
+ !defined(ENABLE_FIELD_INT_62) && \
+ !defined(ENABLE_FIELD_INT_63) && \
+ !defined(ENABLE_FIELD_INT_64)
+#error No fields enabled
+#endif
+
+#if defined(ENABLE_FIELD_INT_2) || \
+ defined(ENABLE_FIELD_INT_3) || \
+ defined(ENABLE_FIELD_INT_4) || \
+ defined(ENABLE_FIELD_INT_5) || \
+ defined(ENABLE_FIELD_INT_6) || \
+ defined(ENABLE_FIELD_INT_7) || \
+ defined(ENABLE_FIELD_INT_8)
+#define ENABLE_FIELD_BYTES_INT_1
+#endif
+
+#if defined(ENABLE_FIELD_INT_9) || \
+ defined(ENABLE_FIELD_INT_10) || \
+ defined(ENABLE_FIELD_INT_11) || \
+ defined(ENABLE_FIELD_INT_12) || \
+ defined(ENABLE_FIELD_INT_13) || \
+ defined(ENABLE_FIELD_INT_14) || \
+ defined(ENABLE_FIELD_INT_15) || \
+ defined(ENABLE_FIELD_INT_16)
+#define ENABLE_FIELD_BYTES_INT_2
+#endif
+
+#if defined(ENABLE_FIELD_INT_17) || \
+ defined(ENABLE_FIELD_INT_18) || \
+ defined(ENABLE_FIELD_INT_19) || \
+ defined(ENABLE_FIELD_INT_20) || \
+ defined(ENABLE_FIELD_INT_21) || \
+ defined(ENABLE_FIELD_INT_22) || \
+ defined(ENABLE_FIELD_INT_23) || \
+ defined(ENABLE_FIELD_INT_24)
+#define ENABLE_FIELD_BYTES_INT_3
+#endif
+
+#if defined(ENABLE_FIELD_INT_25) || \
+ defined(ENABLE_FIELD_INT_26) || \
+ defined(ENABLE_FIELD_INT_27) || \
+ defined(ENABLE_FIELD_INT_28) || \
+ defined(ENABLE_FIELD_INT_29) || \
+ defined(ENABLE_FIELD_INT_30) || \
+ defined(ENABLE_FIELD_INT_31) || \
+ defined(ENABLE_FIELD_INT_32)
+#define ENABLE_FIELD_BYTES_INT_4
+#endif
+
+#if defined(ENABLE_FIELD_INT_33) || \
+ defined(ENABLE_FIELD_INT_34) || \
+ defined(ENABLE_FIELD_INT_35) || \
+ defined(ENABLE_FIELD_INT_36) || \
+ defined(ENABLE_FIELD_INT_37) || \
+ defined(ENABLE_FIELD_INT_38) || \
+ defined(ENABLE_FIELD_INT_39) || \
+ defined(ENABLE_FIELD_INT_40)
+#define ENABLE_FIELD_BYTES_INT_5
+#endif
+
+#if defined(ENABLE_FIELD_INT_41) || \
+ defined(ENABLE_FIELD_INT_42) || \
+ defined(ENABLE_FIELD_INT_43) || \
+ defined(ENABLE_FIELD_INT_44) || \
+ defined(ENABLE_FIELD_INT_45) || \
+ defined(ENABLE_FIELD_INT_46) || \
+ defined(ENABLE_FIELD_INT_47) || \
+ defined(ENABLE_FIELD_INT_48)
+#define ENABLE_FIELD_BYTES_INT_6
+#endif
+
+#if defined(ENABLE_FIELD_INT_49) || \
+ defined(ENABLE_FIELD_INT_50) || \
+ defined(ENABLE_FIELD_INT_51) || \
+ defined(ENABLE_FIELD_INT_52) || \
+ defined(ENABLE_FIELD_INT_53) || \
+ defined(ENABLE_FIELD_INT_54) || \
+ defined(ENABLE_FIELD_INT_55) || \
+ defined(ENABLE_FIELD_INT_56)
+#define ENABLE_FIELD_BYTES_INT_7
+#endif
+
+#if defined(ENABLE_FIELD_INT_57) || \
+ defined(ENABLE_FIELD_INT_58) || \
+ defined(ENABLE_FIELD_INT_59) || \
+ defined(ENABLE_FIELD_INT_60) || \
+ defined(ENABLE_FIELD_INT_61) || \
+ defined(ENABLE_FIELD_INT_62) || \
+ defined(ENABLE_FIELD_INT_63) || \
+ defined(ENABLE_FIELD_INT_64)
+#define ENABLE_FIELD_BYTES_INT_8
+#endif
+#endif // _MINISKETCH_FIELDDEFINES_H_
diff --git a/src/fields/clmul_1byte.cpp b/src/fields/clmul_1byte.cpp
new file mode 100644
index 00000000..8826af96
--- /dev/null
+++ b/src/fields/clmul_1byte.cpp
@@ -0,0 +1,119 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* This file was substantially auto-generated by doc/gen_params.sage. */
+#include "../fielddefines.h"
+
+#if defined(ENABLE_FIELD_BYTES_INT_1)
+
+#include "clmul_common_impl.h"
+
+#include "../int_utils.h"
+#include "../lintrans.h"
+#include "../sketch_impl.h"
+
+#endif
+
+#include "../sketch.h"
+
+namespace {
+#ifdef ENABLE_FIELD_INT_2
+// 2 bit field
+typedef RecLinTrans<uint8_t, 2> StatTableTRI2;
+constexpr StatTableTRI2 SQR_TABLE_TRI2({0x1, 0x3});
+constexpr StatTableTRI2 QRT_TABLE_TRI2({0x2, 0});
+typedef FieldTri<uint8_t, 2, 1, StatTableTRI2, &SQR_TABLE_TRI2, &QRT_TABLE_TRI2, &QRT_TABLE_TRI2, &QRT_TABLE_TRI2, &QRT_TABLE_TRI2, &QRT_TABLE_TRI2, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri2;
+#endif
+
+#ifdef ENABLE_FIELD_INT_3
+// 3 bit field
+typedef RecLinTrans<uint8_t, 3> StatTableTRI3;
+constexpr StatTableTRI3 SQR_TABLE_TRI3({0x1, 0x4, 0x6});
+constexpr StatTableTRI3 QRT_TABLE_TRI3({0, 0x4, 0x6});
+typedef FieldTri<uint8_t, 3, 1, StatTableTRI3, &SQR_TABLE_TRI3, &QRT_TABLE_TRI3, &QRT_TABLE_TRI3, &QRT_TABLE_TRI3, &QRT_TABLE_TRI3, &QRT_TABLE_TRI3, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri3;
+#endif
+
+#ifdef ENABLE_FIELD_INT_4
+// 4 bit field
+typedef RecLinTrans<uint8_t, 4> StatTableTRI4;
+constexpr StatTableTRI4 SQR_TABLE_TRI4({0x1, 0x4, 0x3, 0xc});
+constexpr StatTableTRI4 QRT_TABLE_TRI4({0x6, 0xa, 0x8, 0});
+typedef FieldTri<uint8_t, 4, 1, StatTableTRI4, &SQR_TABLE_TRI4, &QRT_TABLE_TRI4, &QRT_TABLE_TRI4, &QRT_TABLE_TRI4, &QRT_TABLE_TRI4, &QRT_TABLE_TRI4, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri4;
+#endif
+
+#ifdef ENABLE_FIELD_INT_5
+// 5 bit field
+typedef RecLinTrans<uint8_t, 5> StatTable5;
+constexpr StatTable5 SQR_TABLE_5({0x1, 0x4, 0x10, 0xa, 0xd});
+constexpr StatTable5 SQR2_TABLE_5({0x1, 0x10, 0xd, 0xe, 0x1b});
+constexpr StatTable5 QRT_TABLE_5({0x14, 0x8, 0xa, 0, 0xe});
+typedef Field<uint8_t, 5, 5, StatTable5, &SQR_TABLE_5, &SQR2_TABLE_5, &QRT_TABLE_5, &QRT_TABLE_5, &QRT_TABLE_5, &QRT_TABLE_5, IdTrans, &ID_TRANS, &ID_TRANS> Field5;
+typedef FieldTri<uint8_t, 5, 2, RecLinTrans<uint8_t, 5>, &SQR_TABLE_5, &SQR2_TABLE_5, &QRT_TABLE_5, &QRT_TABLE_5, &QRT_TABLE_5, &QRT_TABLE_5, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri5;
+#endif
+
+#ifdef ENABLE_FIELD_INT_6
+// 6 bit field
+typedef RecLinTrans<uint8_t, 6> StatTableTRI6;
+constexpr StatTableTRI6 SQR_TABLE_TRI6({0x1, 0x4, 0x10, 0x3, 0xc, 0x30});
+constexpr StatTableTRI6 SQR2_TABLE_TRI6({0x1, 0x10, 0xc, 0x5, 0x13, 0x3c});
+constexpr StatTableTRI6 QRT_TABLE_TRI6({0x3a, 0x26, 0x24, 0x14, 0x20, 0});
+typedef FieldTri<uint8_t, 6, 1, StatTableTRI6, &SQR_TABLE_TRI6, &SQR2_TABLE_TRI6, &QRT_TABLE_TRI6, &QRT_TABLE_TRI6, &QRT_TABLE_TRI6, &QRT_TABLE_TRI6, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri6;
+#endif
+
+#ifdef ENABLE_FIELD_INT_7
+// 7 bit field
+typedef RecLinTrans<uint8_t, 4, 3> StatTableTRI7;
+constexpr StatTableTRI7 SQR_TABLE_TRI7({0x1, 0x4, 0x10, 0x40, 0x6, 0x18, 0x60});
+constexpr StatTableTRI7 SQR2_TABLE_TRI7({0x1, 0x10, 0x6, 0x60, 0x14, 0x46, 0x78});
+constexpr StatTableTRI7 QRT_TABLE_TRI7({0, 0x14, 0x16, 0x72, 0x12, 0x40, 0x7a});
+typedef FieldTri<uint8_t, 7, 1, StatTableTRI7, &SQR_TABLE_TRI7, &SQR2_TABLE_TRI7, &QRT_TABLE_TRI7, &QRT_TABLE_TRI7, &QRT_TABLE_TRI7, &QRT_TABLE_TRI7, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri7;
+#endif
+
+#ifdef ENABLE_FIELD_INT_8
+// 8 bit field
+typedef RecLinTrans<uint8_t, 4, 4> StatTable8;
+constexpr StatTable8 SQR_TABLE_8({0x1, 0x4, 0x10, 0x40, 0x1b, 0x6c, 0xab, 0x9a});
+constexpr StatTable8 SQR2_TABLE_8({0x1, 0x10, 0x1b, 0xab, 0x5e, 0x97, 0xb3, 0xc5});
+constexpr StatTable8 QRT_TABLE_8({0xbc, 0x2a, 0x28, 0x86, 0x2c, 0xde, 0x8e, 0});
+typedef Field<uint8_t, 8, 27, StatTable8, &SQR_TABLE_8, &SQR2_TABLE_8, &QRT_TABLE_8, &QRT_TABLE_8, &QRT_TABLE_8, &QRT_TABLE_8, IdTrans, &ID_TRANS, &ID_TRANS> Field8;
+#endif
+}
+
+Sketch* ConstructClMul1Byte(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_5
+ case 5: return new SketchImpl<Field5>(implementation, 5);
+#endif
+#ifdef ENABLE_FIELD_INT_8
+ case 8: return new SketchImpl<Field8>(implementation, 8);
+#endif
+ }
+ return nullptr;
+}
+
+Sketch* ConstructClMulTri1Byte(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_2
+ case 2: return new SketchImpl<FieldTri2>(implementation, 2);
+#endif
+#ifdef ENABLE_FIELD_INT_3
+ case 3: return new SketchImpl<FieldTri3>(implementation, 3);
+#endif
+#ifdef ENABLE_FIELD_INT_4
+ case 4: return new SketchImpl<FieldTri4>(implementation, 4);
+#endif
+#ifdef ENABLE_FIELD_INT_5
+ case 5: return new SketchImpl<FieldTri5>(implementation, 5);
+#endif
+#ifdef ENABLE_FIELD_INT_6
+ case 6: return new SketchImpl<FieldTri6>(implementation, 6);
+#endif
+#ifdef ENABLE_FIELD_INT_7
+ case 7: return new SketchImpl<FieldTri7>(implementation, 7);
+#endif
+ }
+ return nullptr;
+}
diff --git a/src/fields/clmul_2bytes.cpp b/src/fields/clmul_2bytes.cpp
new file mode 100644
index 00000000..43930254
--- /dev/null
+++ b/src/fields/clmul_2bytes.cpp
@@ -0,0 +1,154 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* This file was substantially auto-generated by doc/gen_params.sage. */
+#include "../fielddefines.h"
+
+#if defined(ENABLE_FIELD_BYTES_INT_2)
+
+#include "clmul_common_impl.h"
+
+#include "../int_utils.h"
+#include "../lintrans.h"
+#include "../sketch_impl.h"
+
+#endif
+
+#include "../sketch.h"
+
+namespace {
+#ifdef ENABLE_FIELD_INT_9
+// 9 bit field
+typedef RecLinTrans<uint16_t, 5, 4> StatTableTRI9;
+constexpr StatTableTRI9 SQR_TABLE_TRI9({0x1, 0x4, 0x10, 0x40, 0x100, 0x6, 0x18, 0x60, 0x180});
+constexpr StatTableTRI9 SQR2_TABLE_TRI9({0x1, 0x10, 0x100, 0x18, 0x180, 0x14, 0x140, 0x1e, 0x1e0});
+constexpr StatTableTRI9 SQR4_TABLE_TRI9({0x1, 0x180, 0x1e0, 0x198, 0x1fe, 0x80, 0xa0, 0x88, 0xaa});
+constexpr StatTableTRI9 QRT_TABLE_TRI9({0, 0x4e, 0x4c, 0x1aa, 0x48, 0x22, 0x1a2, 0x100, 0x58});
+typedef FieldTri<uint16_t, 9, 1, StatTableTRI9, &SQR_TABLE_TRI9, &SQR2_TABLE_TRI9, &SQR4_TABLE_TRI9, &QRT_TABLE_TRI9, &QRT_TABLE_TRI9, &QRT_TABLE_TRI9, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri9;
+#endif
+
+#ifdef ENABLE_FIELD_INT_10
+// 10 bit field
+typedef RecLinTrans<uint16_t, 5, 5> StatTable10;
+constexpr StatTable10 SQR_TABLE_10({0x1, 0x4, 0x10, 0x40, 0x100, 0x9, 0x24, 0x90, 0x240, 0x112});
+constexpr StatTable10 SQR2_TABLE_10({0x1, 0x10, 0x100, 0x24, 0x240, 0x41, 0x19, 0x190, 0x136, 0x344});
+constexpr StatTable10 SQR4_TABLE_10({0x1, 0x240, 0x136, 0x141, 0x35d, 0x18, 0x265, 0x2e6, 0x227, 0x36b});
+constexpr StatTable10 QRT_TABLE_10({0xec, 0x86, 0x84, 0x30e, 0x80, 0x3c2, 0x306, 0, 0x90, 0x296});
+typedef Field<uint16_t, 10, 9, StatTable10, &SQR_TABLE_10, &SQR2_TABLE_10, &SQR4_TABLE_10, &QRT_TABLE_10, &QRT_TABLE_10, &QRT_TABLE_10, IdTrans, &ID_TRANS, &ID_TRANS> Field10;
+typedef FieldTri<uint16_t, 10, 3, RecLinTrans<uint16_t, 5, 5>, &SQR_TABLE_10, &SQR2_TABLE_10, &SQR4_TABLE_10, &QRT_TABLE_10, &QRT_TABLE_10, &QRT_TABLE_10, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri10;
+#endif
+
+#ifdef ENABLE_FIELD_INT_11
+// 11 bit field
+typedef RecLinTrans<uint16_t, 6, 5> StatTable11;
+constexpr StatTable11 SQR_TABLE_11({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0xa, 0x28, 0xa0, 0x280, 0x205});
+constexpr StatTable11 SQR2_TABLE_11({0x1, 0x10, 0x100, 0xa, 0xa0, 0x205, 0x44, 0x440, 0x428, 0x2a8, 0x291});
+constexpr StatTable11 SQR4_TABLE_11({0x1, 0xa0, 0x428, 0x1a, 0x645, 0x3a9, 0x144, 0x2d5, 0x9e, 0x4e7, 0x649});
+constexpr StatTable11 QRT_TABLE_11({0x734, 0x48, 0x4a, 0x1de, 0x4e, 0x35e, 0x1d6, 0x200, 0x5e, 0, 0x37e});
+typedef Field<uint16_t, 11, 5, StatTable11, &SQR_TABLE_11, &SQR2_TABLE_11, &SQR4_TABLE_11, nullptr, nullptr, &QRT_TABLE_11, IdTrans, &ID_TRANS, &ID_TRANS> Field11;
+typedef FieldTri<uint16_t, 11, 2, RecLinTrans<uint16_t, 6, 5>, &SQR_TABLE_11, &SQR2_TABLE_11, &SQR4_TABLE_11, &QRT_TABLE_11, &QRT_TABLE_11, &QRT_TABLE_11, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri11;
+#endif
+
+#ifdef ENABLE_FIELD_INT_12
+// 12 bit field
+typedef RecLinTrans<uint16_t, 6, 6> StatTable12;
+constexpr StatTable12 SQR_TABLE_12({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x9, 0x24, 0x90, 0x240, 0x900, 0x412});
+constexpr StatTable12 SQR2_TABLE_12({0x1, 0x10, 0x100, 0x9, 0x90, 0x900, 0x41, 0x410, 0x124, 0x249, 0x482, 0x804});
+constexpr StatTable12 SQR4_TABLE_12({0x1, 0x90, 0x124, 0x8, 0x480, 0x920, 0x40, 0x412, 0x924, 0x200, 0x82, 0x904});
+constexpr StatTable12 QRT_TABLE_12({0x48, 0xc10, 0xc12, 0x208, 0xc16, 0xd82, 0x200, 0x110, 0xc06, 0, 0xda2, 0x5a4});
+typedef Field<uint16_t, 12, 9, StatTable12, &SQR_TABLE_12, &SQR2_TABLE_12, &SQR4_TABLE_12, &QRT_TABLE_12, &QRT_TABLE_12, &QRT_TABLE_12, IdTrans, &ID_TRANS, &ID_TRANS> Field12;
+typedef FieldTri<uint16_t, 12, 3, RecLinTrans<uint16_t, 6, 6>, &SQR_TABLE_12, &SQR2_TABLE_12, &SQR4_TABLE_12, &QRT_TABLE_12, &QRT_TABLE_12, &QRT_TABLE_12, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri12;
+#endif
+
+#ifdef ENABLE_FIELD_INT_13
+// 13 bit field
+typedef RecLinTrans<uint16_t, 5, 4, 4> StatTable13;
+constexpr StatTable13 SQR_TABLE_13({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x36, 0xd8, 0x360, 0xd80, 0x161b, 0x185a});
+constexpr StatTable13 SQR2_TABLE_13({0x1, 0x10, 0x100, 0x1000, 0xd8, 0xd80, 0x185a, 0x514, 0x1176, 0x17b8, 0x1b75, 0x17ff, 0x1f05});
+constexpr StatTable13 SQR4_TABLE_13({0x1, 0xd8, 0x1176, 0x1f05, 0xd96, 0x18e8, 0x68, 0xbdb, 0x1a61, 0x1af2, 0x1a37, 0x3b9, 0x1440});
+constexpr StatTable13 QRT_TABLE_13({0xcfc, 0x1500, 0x1502, 0x382, 0x1506, 0x149c, 0x38a, 0x118, 0x1516, 0, 0x14bc, 0x100e, 0x3ca});
+typedef Field<uint16_t, 13, 27, StatTable13, &SQR_TABLE_13, &SQR2_TABLE_13, &SQR4_TABLE_13, &QRT_TABLE_13, &QRT_TABLE_13, &QRT_TABLE_13, IdTrans, &ID_TRANS, &ID_TRANS> Field13;
+#endif
+
+#ifdef ENABLE_FIELD_INT_14
+// 14 bit field
+typedef RecLinTrans<uint16_t, 5, 5, 4> StatTable14;
+constexpr StatTable14 SQR_TABLE_14({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x21, 0x84, 0x210, 0x840, 0x2100, 0x442, 0x1108});
+constexpr StatTable14 SQR2_TABLE_14({0x1, 0x10, 0x100, 0x1000, 0x84, 0x840, 0x442, 0x401, 0x31, 0x310, 0x3100, 0x118c, 0x1844, 0x486});
+constexpr StatTable14 SQR4_TABLE_14({0x1, 0x84, 0x31, 0x1844, 0x501, 0x15ce, 0x3552, 0x3101, 0x8c5, 0x3a5, 0x1cf3, 0xd74, 0xc8a, 0x3411});
+constexpr StatTable14 QRT_TABLE_14({0x13f2, 0x206, 0x204, 0x3e06, 0x200, 0x1266, 0x3e0e, 0x114, 0x210, 0, 0x1246, 0x2848, 0x3e4e, 0x2258});
+typedef Field<uint16_t, 14, 33, StatTable14, &SQR_TABLE_14, &SQR2_TABLE_14, &SQR4_TABLE_14, &QRT_TABLE_14, &QRT_TABLE_14, &QRT_TABLE_14, IdTrans, &ID_TRANS, &ID_TRANS> Field14;
+typedef FieldTri<uint16_t, 14, 5, RecLinTrans<uint16_t, 5, 5, 4>, &SQR_TABLE_14, &SQR2_TABLE_14, &SQR4_TABLE_14, &QRT_TABLE_14, &QRT_TABLE_14, &QRT_TABLE_14, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri14;
+#endif
+
+#ifdef ENABLE_FIELD_INT_15
+// 15 bit field
+typedef RecLinTrans<uint16_t, 5, 5, 5> StatTableTRI15;
+constexpr StatTableTRI15 SQR_TABLE_TRI15({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x6, 0x18, 0x60, 0x180, 0x600, 0x1800, 0x6000});
+constexpr StatTableTRI15 SQR2_TABLE_TRI15({0x1, 0x10, 0x100, 0x1000, 0x6, 0x60, 0x600, 0x6000, 0x14, 0x140, 0x1400, 0x4006, 0x78, 0x780, 0x7800});
+constexpr StatTableTRI15 SQR4_TABLE_TRI15({0x1, 0x6, 0x14, 0x78, 0x110, 0x660, 0x1540, 0x7f80, 0x106, 0x614, 0x1478, 0x7910, 0x1666, 0x7554, 0x3ffe});
+constexpr StatTableTRI15 QRT_TABLE_TRI15({0, 0x114, 0x116, 0x428, 0x112, 0x137a, 0x420, 0x6d62, 0x102, 0x73a, 0x135a, 0x6460, 0x460, 0x4000, 0x6de2});
+typedef FieldTri<uint16_t, 15, 1, StatTableTRI15, &SQR_TABLE_TRI15, &SQR2_TABLE_TRI15, &SQR4_TABLE_TRI15, &QRT_TABLE_TRI15, &QRT_TABLE_TRI15, &QRT_TABLE_TRI15, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri15;
+#endif
+
+#ifdef ENABLE_FIELD_INT_16
+// 16 bit field
+typedef RecLinTrans<uint16_t, 6, 5, 5> StatTable16;
+constexpr StatTable16 SQR_TABLE_16({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x2b, 0xac, 0x2b0, 0xac0, 0x2b00, 0xac00, 0xb056, 0xc10e});
+constexpr StatTable16 SQR2_TABLE_16({0x1, 0x10, 0x100, 0x1000, 0x2b, 0x2b0, 0x2b00, 0xb056, 0x445, 0x4450, 0x45ac, 0x5a6c, 0xa647, 0x657e, 0x571a, 0x7127});
+constexpr StatTable16 SQR4_TABLE_16({0x1, 0x2b, 0x445, 0xa647, 0x12a1, 0xf69d, 0x7f07, 0x9825, 0x6fad, 0x399d, 0xb515, 0xd7d1, 0x3fb4, 0x4b06, 0xe4df, 0x93c7});
+constexpr StatTable16 QRT_TABLE_16({0x732, 0x72b8, 0x72ba, 0x7e96, 0x72be, 0x78b2, 0x7e9e, 0x8cba, 0x72ae, 0xfa24, 0x7892, 0x5892, 0x7ede, 0xbec6, 0x8c3a, 0});
+typedef Field<uint16_t, 16, 43, StatTable16, &SQR_TABLE_16, &SQR2_TABLE_16, &SQR4_TABLE_16, &QRT_TABLE_16, &QRT_TABLE_16, &QRT_TABLE_16, IdTrans, &ID_TRANS, &ID_TRANS> Field16;
+#endif
+}
+
+Sketch* ConstructClMul2Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_10
+ case 10: return new SketchImpl<Field10>(implementation, 10);
+#endif
+#ifdef ENABLE_FIELD_INT_11
+ case 11: return new SketchImpl<Field11>(implementation, 11);
+#endif
+#ifdef ENABLE_FIELD_INT_12
+ case 12: return new SketchImpl<Field12>(implementation, 12);
+#endif
+#ifdef ENABLE_FIELD_INT_13
+ case 13: return new SketchImpl<Field13>(implementation, 13);
+#endif
+#ifdef ENABLE_FIELD_INT_14
+ case 14: return new SketchImpl<Field14>(implementation, 14);
+#endif
+#ifdef ENABLE_FIELD_INT_16
+ case 16: return new SketchImpl<Field16>(implementation, 16);
+#endif
+ }
+ return nullptr;
+}
+
+Sketch* ConstructClMulTri2Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_9
+ case 9: return new SketchImpl<FieldTri9>(implementation, 9);
+#endif
+#ifdef ENABLE_FIELD_INT_10
+ case 10: return new SketchImpl<FieldTri10>(implementation, 10);
+#endif
+#ifdef ENABLE_FIELD_INT_11
+ case 11: return new SketchImpl<FieldTri11>(implementation, 11);
+#endif
+#ifdef ENABLE_FIELD_INT_12
+ case 12: return new SketchImpl<FieldTri12>(implementation, 12);
+#endif
+#ifdef ENABLE_FIELD_INT_14
+ case 14: return new SketchImpl<FieldTri14>(implementation, 14);
+#endif
+#ifdef ENABLE_FIELD_INT_15
+ case 15: return new SketchImpl<FieldTri15>(implementation, 15);
+#endif
+ }
+ return nullptr;
+}
diff --git a/src/fields/clmul_3bytes.cpp b/src/fields/clmul_3bytes.cpp
new file mode 100644
index 00000000..b473f66b
--- /dev/null
+++ b/src/fields/clmul_3bytes.cpp
@@ -0,0 +1,166 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* This file was substantially auto-generated by doc/gen_params.sage. */
+#include "../fielddefines.h"
+
+#if defined(ENABLE_FIELD_BYTES_INT_3)
+
+#include "clmul_common_impl.h"
+
+#include "../int_utils.h"
+#include "../lintrans.h"
+#include "../sketch_impl.h"
+
+#endif
+
+#include "../sketch.h"
+
+namespace {
+#ifdef ENABLE_FIELD_INT_17
+// 17 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 5> StatTable17;
+constexpr StatTable17 SQR_TABLE_17({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x12, 0x48, 0x120, 0x480, 0x1200, 0x4800, 0x12000, 0x8012});
+constexpr StatTable17 SQR2_TABLE_17({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x48, 0x480, 0x4800, 0x8012, 0x104, 0x1040, 0x10400, 0x4048, 0x492, 0x4920, 0x9212, 0x12104});
+constexpr StatTable17 SQR4_TABLE_17({0x1, 0x10000, 0x8012, 0x4048, 0x12104, 0x1480, 0x5840, 0x14d20, 0x19202, 0x8112, 0x44c8, 0x13144, 0x5da0, 0x15850, 0x1cd7a, 0x1d34e, 0x1a484});
+constexpr StatTable17 SQR8_TABLE_17({0x1, 0x1a484, 0x1f24a, 0x1d572, 0x1eec4, 0x15448, 0xf9de, 0x9af0, 0x1ab78, 0x6048, 0xdc9a, 0x1eb24, 0x2ef4, 0x7c5e, 0x170b2, 0x16c1a, 0xa660});
+constexpr StatTable17 QRT_TABLE_17({0, 0x4c3e, 0x4c3c, 0x1a248, 0x4c38, 0x428, 0x1a240, 0x1b608, 0x4c28, 0x206, 0x408, 0x4000, 0x1a200, 0x18006, 0x1b688, 0x14d2e, 0x4d28});
+typedef Field<uint32_t, 17, 9, StatTable17, &SQR_TABLE_17, &SQR2_TABLE_17, &SQR4_TABLE_17, &SQR8_TABLE_17, &QRT_TABLE_17, &QRT_TABLE_17, IdTrans, &ID_TRANS, &ID_TRANS> Field17;
+typedef FieldTri<uint32_t, 17, 3, RecLinTrans<uint32_t, 6, 6, 5>, &SQR_TABLE_17, &SQR2_TABLE_17, &SQR4_TABLE_17, &SQR8_TABLE_17, &QRT_TABLE_17, &QRT_TABLE_17, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri17;
+#endif
+
+#ifdef ENABLE_FIELD_INT_18
+// 18 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 6> StatTable18;
+constexpr StatTable18 SQR_TABLE_18({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x9, 0x24, 0x90, 0x240, 0x900, 0x2400, 0x9000, 0x24000, 0x10012});
+constexpr StatTable18 SQR2_TABLE_18({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x24, 0x240, 0x2400, 0x24000, 0x41, 0x410, 0x4100, 0x1009, 0x10090, 0x924, 0x9240, 0x12412, 0x24104});
+constexpr StatTable18 SQR4_TABLE_18({0x1, 0x10000, 0x24000, 0x1009, 0x12412, 0x124, 0x201, 0x10480, 0x24820, 0x241, 0x10410, 0x24924, 0x8, 0x12, 0x20024, 0x8048, 0x12082, 0x920});
+constexpr StatTable18 SQR8_TABLE_18({0x1, 0x12082, 0x20904, 0x1000, 0x92, 0x904, 0x240, 0x12012, 0x4104, 0x41, 0x10080, 0x4924, 0x1009, 0x2412, 0x24804, 0x9240, 0x12410, 0x20});
+constexpr StatTable18 QRT_TABLE_18({0x9208, 0x422, 0x420, 0x8048, 0x424, 0x68b0, 0x8040, 0x30086, 0x434, 0x1040, 0x6890, 0x30ca2, 0x8000, 0x32896, 0x30006, 0, 0x534, 0x20532});
+typedef Field<uint32_t, 18, 9, StatTable18, &SQR_TABLE_18, &SQR2_TABLE_18, &SQR4_TABLE_18, &SQR8_TABLE_18, &QRT_TABLE_18, &QRT_TABLE_18, IdTrans, &ID_TRANS, &ID_TRANS> Field18;
+typedef FieldTri<uint32_t, 18, 3, RecLinTrans<uint32_t, 6, 6, 6>, &SQR_TABLE_18, &SQR2_TABLE_18, &SQR4_TABLE_18, &SQR8_TABLE_18, &QRT_TABLE_18, &QRT_TABLE_18, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri18;
+#endif
+
+#ifdef ENABLE_FIELD_INT_19
+// 19 bit field
+typedef RecLinTrans<uint32_t, 5, 5, 5, 4> StatTable19;
+constexpr StatTable19 SQR_TABLE_19({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x4e, 0x138, 0x4e0, 0x1380, 0x4e00, 0x13800, 0x4e000, 0x3804e, 0x6011f});
+constexpr StatTable19 SQR2_TABLE_19({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x4e, 0x4e0, 0x4e00, 0x4e000, 0x6011f, 0x1054, 0x10540, 0x544e, 0x544e0, 0x44f76, 0x4f658, 0x7649f, 0x6481a, 0x48004});
+constexpr StatTable19 SQR4_TABLE_19({0x1, 0x10000, 0x4e000, 0x544e, 0x7649f, 0x15f0, 0x5afa, 0x35b7d, 0x17dca, 0x7390f, 0x151ae, 0x3902b, 0x41e9c, 0x7f117, 0x23ec7, 0x62c2f, 0x5e852, 0x69238, 0x775c});
+constexpr StatTable19 SQR8_TABLE_19({0x1, 0x5e852, 0x394a3, 0x29f41, 0x618e5, 0x4210, 0x7add9, 0x31105, 0x5d098, 0x7bb13, 0x44f00, 0x966, 0x11ae6, 0x70901, 0x664bf, 0x67449, 0x3d2bf, 0x4cbf9, 0x54e0c});
+constexpr StatTable19 QRT_TABLE_19({0x5d6b0, 0x2f476, 0x2f474, 0x1d6a2, 0x2f470, 0x42a, 0x1d6aa, 0x1060, 0x2f460, 0x19e92, 0x40a, 0x1da98, 0x1d6ea, 0x28c78, 0x10e0, 0xf56a, 0x2f560, 0, 0x19c92});
+typedef Field<uint32_t, 19, 39, StatTable19, &SQR_TABLE_19, &SQR2_TABLE_19, &SQR4_TABLE_19, &SQR8_TABLE_19, &QRT_TABLE_19, &QRT_TABLE_19, IdTrans, &ID_TRANS, &ID_TRANS> Field19;
+#endif
+
+#ifdef ENABLE_FIELD_INT_20
+// 20 bit field
+typedef RecLinTrans<uint32_t, 5, 5, 5, 5> StatTable20;
+constexpr StatTable20 SQR_TABLE_20({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x9, 0x24, 0x90, 0x240, 0x900, 0x2400, 0x9000, 0x24000, 0x90000, 0x40012});
+constexpr StatTable20 SQR2_TABLE_20({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x9, 0x90, 0x900, 0x9000, 0x90000, 0x41, 0x410, 0x4100, 0x41000, 0x10024, 0x249, 0x2490, 0x24900, 0x49012, 0x90104});
+constexpr StatTable20 SQR4_TABLE_20({0x1, 0x10000, 0x9000, 0x4100, 0x2490, 0x1001, 0x10900, 0x9410, 0x4349, 0x92594, 0x91, 0x10041, 0x19024, 0x4d112, 0x2599, 0x91091, 0x51941, 0x3dd34, 0x5d34b, 0x9b494});
+constexpr StatTable20 SQR8_TABLE_20({0x1, 0x51941, 0x880b5, 0x66d0, 0x46103, 0x19025, 0x45a49, 0x8a4b4, 0x80b45, 0x81f9f, 0xb081, 0x41040, 0xd19f5, 0xc11be, 0x4634b, 0xd8d70, 0x11027, 0xf8651, 0x141fa, 0xdc63});
+constexpr StatTable20 QRT_TABLE_20({0xc5dea, 0xc0110, 0xc0112, 0xe11de, 0xc0116, 0x24814, 0xe11d6, 0x20080, 0xc0106, 0xfe872, 0x24834, 0xe4106, 0xe1196, 0x1d9a4, 0x20000, 0x31190, 0xc0006, 0, 0xfea72, 0x7ea74});
+typedef Field<uint32_t, 20, 9, StatTable20, &SQR_TABLE_20, &SQR2_TABLE_20, &SQR4_TABLE_20, &SQR8_TABLE_20, &QRT_TABLE_20, &QRT_TABLE_20, IdTrans, &ID_TRANS, &ID_TRANS> Field20;
+typedef FieldTri<uint32_t, 20, 3, RecLinTrans<uint32_t, 5, 5, 5, 5>, &SQR_TABLE_20, &SQR2_TABLE_20, &SQR4_TABLE_20, &SQR8_TABLE_20, &QRT_TABLE_20, &QRT_TABLE_20, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri20;
+#endif
+
+#ifdef ENABLE_FIELD_INT_21
+// 21 bit field
+typedef RecLinTrans<uint32_t, 6, 5, 5, 5> StatTable21;
+constexpr StatTable21 SQR_TABLE_21({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0xa, 0x28, 0xa0, 0x280, 0xa00, 0x2800, 0xa000, 0x28000, 0xa0000, 0x80005});
+constexpr StatTable21 SQR2_TABLE_21({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x28, 0x280, 0x2800, 0x28000, 0x80005, 0x44, 0x440, 0x4400, 0x44000, 0x4000a, 0xaa, 0xaa0, 0xaa00, 0xaa000, 0xa0011});
+constexpr StatTable21 SQR4_TABLE_21({0x1, 0x10000, 0x2800, 0x440, 0xaa, 0xa0011, 0x101000, 0x28280, 0x4444, 0x40aaa, 0xaa101, 0x128, 0x8002d, 0xc4005, 0x4ea00, 0xba10, 0x101290, 0x1282c4, 0x6c44e, 0xeeeaa, 0xbaaa1});
+constexpr StatTable21 SQR8_TABLE_21({0x1, 0x101290, 0xc412d, 0x1ab101, 0x986d1, 0x1c6cc5, 0x3aa8c, 0x14b0fe, 0x1e7301, 0xb491d, 0x10d23e, 0xa4015, 0x4c2fa, 0xce8e5, 0xadfd9, 0xf110, 0x5220c, 0xf225f, 0xb8bdb, 0x159467, 0xc0df9});
+constexpr StatTable21 QRT_TABLE_21({0x1bd5fc, 0xbc196, 0xbc194, 0x74b96, 0xbc190, 0x1048, 0x74b9e, 0x672c8, 0xbc180, 0x4080, 0x1068, 0xc8200, 0x74bde, 0x64280, 0x67248, 0xc4280, 0xbc080, 0x80000, 0x4280, 0, 0x1468});
+typedef Field<uint32_t, 21, 5, StatTable21, &SQR_TABLE_21, &SQR2_TABLE_21, &SQR4_TABLE_21, &SQR8_TABLE_21, &QRT_TABLE_21, &QRT_TABLE_21, IdTrans, &ID_TRANS, &ID_TRANS> Field21;
+typedef FieldTri<uint32_t, 21, 2, RecLinTrans<uint32_t, 6, 5, 5, 5>, &SQR_TABLE_21, &SQR2_TABLE_21, &SQR4_TABLE_21, &SQR8_TABLE_21, &QRT_TABLE_21, &QRT_TABLE_21, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri21;
+#endif
+
+#ifdef ENABLE_FIELD_INT_22
+// 22 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 5, 5> StatTableTRI22;
+constexpr StatTableTRI22 SQR_TABLE_TRI22({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x3, 0xc, 0x30, 0xc0, 0x300, 0xc00, 0x3000, 0xc000, 0x30000, 0xc0000, 0x300000});
+constexpr StatTableTRI22 SQR2_TABLE_TRI22({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0xc, 0xc0, 0xc00, 0xc000, 0xc0000, 0x5, 0x50, 0x500, 0x5000, 0x50000, 0x100003, 0x3c, 0x3c0, 0x3c00, 0x3c000, 0x3c0000});
+constexpr StatTableTRI22 SQR4_TABLE_TRI22({0x1, 0x10000, 0xc00, 0x50, 0x100003, 0x3c000, 0x1100, 0xcc, 0xc0005, 0x55000, 0x3fc0, 0x101, 0x1000c, 0xc0c00, 0x5050, 0x1003c3, 0x3c011, 0x111100, 0xcccc, 0xc0555, 0x15503f, 0x3fffc0});
+constexpr StatTableTRI22 SQR8_TABLE_TRI22({0x1, 0x3c011, 0x3ec1, 0x101103, 0x14503e, 0x28282, 0xd0009, 0x1d9c, 0xcc598, 0x25c81, 0x47304, 0xc0004, 0x3cc41, 0xcf758, 0x11415f, 0x1d11f7, 0x128280, 0x1b9027, 0x1070ce, 0x10eb5e, 0x5c0ec, 0x2097e0});
+constexpr StatTableTRI22 QRT_TABLE_TRI22({0x210d16, 0x104a, 0x1048, 0x4088, 0x104c, 0x200420, 0x4080, 0x492dc, 0x105c, 0x1a67f0, 0x200400, 0x21155c, 0x40c0, 0x20346c, 0x4925c, 0x1af7ac, 0x115c, 0x2274ac, 0x1a65f0, 0x2a65f0, 0x200000, 0});
+typedef FieldTri<uint32_t, 22, 1, StatTableTRI22, &SQR_TABLE_TRI22, &SQR2_TABLE_TRI22, &SQR4_TABLE_TRI22, &SQR8_TABLE_TRI22, &QRT_TABLE_TRI22, &QRT_TABLE_TRI22, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri22;
+#endif
+
+#ifdef ENABLE_FIELD_INT_23
+// 23 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 6, 5> StatTable23;
+constexpr StatTable23 SQR_TABLE_23({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x42, 0x108, 0x420, 0x1080, 0x4200, 0x10800, 0x42000, 0x108000, 0x420000, 0x80042, 0x200108});
+constexpr StatTable23 SQR2_TABLE_23({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x42, 0x420, 0x4200, 0x42000, 0x420000, 0x200108, 0x1004, 0x10040, 0x100400, 0x4042, 0x40420, 0x404200, 0x42108, 0x421080, 0x210908, 0x109004, 0x90002});
+constexpr StatTable23 SQR4_TABLE_23({0x1, 0x10000, 0x4200, 0x1004, 0x40420, 0x210908, 0x52, 0x520000, 0x142400, 0x52148, 0x494202, 0x10c204, 0x1104, 0x40462, 0x630908, 0x100452, 0x562108, 0x1d2402, 0x57348, 0x495626, 0x34c72c, 0x21584e, 0x4614b0});
+constexpr StatTable23 SQR8_TABLE_23({0x1, 0x562108, 0x662840, 0x5304, 0x6d3842, 0x738f46, 0x50472, 0x6ff79e, 0x7cf204, 0x436274, 0x3e4bde, 0x42a93e, 0x147704, 0x6c3810, 0x28bff4, 0x78815c, 0x7ab4b0, 0x62852a, 0x255b30, 0x5653d0, 0x1afd36, 0x5f118, 0x601dd4});
+constexpr StatTable23 QRT_TABLE_23({0, 0x1040, 0x1042, 0x43056, 0x1046, 0x121d76, 0x4305e, 0x40a0, 0x1056, 0x15176, 0x121d56, 0x7ee1f6, 0x4301e, 0x40000, 0x4020, 0x4f0be, 0x1156, 0x7cf0a0, 0x15376, 0x1ee9e8, 0x121956, 0x3ac9f6, 0x7ee9f6});
+typedef Field<uint32_t, 23, 33, StatTable23, &SQR_TABLE_23, &SQR2_TABLE_23, &SQR4_TABLE_23, &SQR8_TABLE_23, &QRT_TABLE_23, &QRT_TABLE_23, IdTrans, &ID_TRANS, &ID_TRANS> Field23;
+typedef FieldTri<uint32_t, 23, 5, RecLinTrans<uint32_t, 6, 6, 6, 5>, &SQR_TABLE_23, &SQR2_TABLE_23, &SQR4_TABLE_23, &SQR8_TABLE_23, nullptr, &QRT_TABLE_23, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri23;
+#endif
+
+#ifdef ENABLE_FIELD_INT_24
+// 24 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 6, 6> StatTable24;
+constexpr StatTable24 SQR_TABLE_24({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1b, 0x6c, 0x1b0, 0x6c0, 0x1b00, 0x6c00, 0x1b000, 0x6c000, 0x1b0000, 0x6c0000, 0xb0001b, 0xc0005a});
+constexpr StatTable24 SQR2_TABLE_24({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1b, 0x1b0, 0x1b00, 0x1b000, 0x1b0000, 0xb0001b, 0x145, 0x1450, 0x14500, 0x145000, 0x45001b, 0x5001dc, 0x1db7, 0x1db70, 0x1db700, 0xdb701b, 0xb7011f, 0x701105});
+constexpr StatTable24 SQR4_TABLE_24({0x1, 0x10000, 0x1b00, 0x145, 0x45001b, 0x1db700, 0x11011, 0x111ab0, 0xb1aa5e, 0x51450e, 0x96db7, 0xb7c60f, 0x1a1a, 0x1a015e, 0x5f5e1b, 0x1ceef2, 0xf30ca2, 0xabbdb4, 0xba1aff, 0xf0bf5e, 0x579fc9, 0xce3da9, 0xa2c07f, 0x71dd40});
+constexpr StatTable24 SQR8_TABLE_24({0x1, 0xf30ca2, 0x573345, 0xb0a14e, 0xafd77d, 0x1419b, 0xb616a2, 0xba7db, 0xbe1560, 0xe0d0a3, 0x15bf5, 0x1056dd, 0xa29845, 0xf83d32, 0x13e0e9, 0xe2d8d3, 0xa10841, 0x57ac5a, 0x1c432f, 0x57044e, 0x454fba, 0x2bb37c, 0xf50fa, 0x85d5b9});
+constexpr StatTable24 QRT_TABLE_24({0x104e, 0xaf42a8, 0xaf42aa, 0xb78186, 0xaf42ae, 0x4090, 0xb7818e, 0x4a37c, 0xaf42be, 0x3688c0, 0x40b0, 0x80080e, 0xb781ce, 0xaf2232, 0x4a3fc, 0x856a82, 0xaf43be, 0x29c970, 0x368ac0, 0x968ace, 0x44b0, 0x77d570, 0x80000e, 0});
+typedef Field<uint32_t, 24, 27, StatTable24, &SQR_TABLE_24, &SQR2_TABLE_24, &SQR4_TABLE_24, &SQR8_TABLE_24, &QRT_TABLE_24, &QRT_TABLE_24, IdTrans, &ID_TRANS, &ID_TRANS> Field24;
+#endif
+}
+
+Sketch* ConstructClMul3Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_17
+ case 17: return new SketchImpl<Field17>(implementation, 17);
+#endif
+#ifdef ENABLE_FIELD_INT_18
+ case 18: return new SketchImpl<Field18>(implementation, 18);
+#endif
+#ifdef ENABLE_FIELD_INT_19
+ case 19: return new SketchImpl<Field19>(implementation, 19);
+#endif
+#ifdef ENABLE_FIELD_INT_20
+ case 20: return new SketchImpl<Field20>(implementation, 20);
+#endif
+#ifdef ENABLE_FIELD_INT_21
+ case 21: return new SketchImpl<Field21>(implementation, 21);
+#endif
+#ifdef ENABLE_FIELD_INT_23
+ case 23: return new SketchImpl<Field23>(implementation, 23);
+#endif
+#ifdef ENABLE_FIELD_INT_24
+ case 24: return new SketchImpl<Field24>(implementation, 24);
+#endif
+ }
+ return nullptr;
+}
+
+Sketch* ConstructClMulTri3Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_17
+ case 17: return new SketchImpl<FieldTri17>(implementation, 17);
+#endif
+#ifdef ENABLE_FIELD_INT_18
+ case 18: return new SketchImpl<FieldTri18>(implementation, 18);
+#endif
+#ifdef ENABLE_FIELD_INT_20
+ case 20: return new SketchImpl<FieldTri20>(implementation, 20);
+#endif
+#ifdef ENABLE_FIELD_INT_21
+ case 21: return new SketchImpl<FieldTri21>(implementation, 21);
+#endif
+#ifdef ENABLE_FIELD_INT_22
+ case 22: return new SketchImpl<FieldTri22>(implementation, 22);
+#endif
+#ifdef ENABLE_FIELD_INT_23
+ case 23: return new SketchImpl<FieldTri23>(implementation, 23);
+#endif
+ }
+ return nullptr;
+}
diff --git a/src/fields/clmul_4bytes.cpp b/src/fields/clmul_4bytes.cpp
new file mode 100644
index 00000000..c6597439
--- /dev/null
+++ b/src/fields/clmul_4bytes.cpp
@@ -0,0 +1,158 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* This file was substantially auto-generated by doc/gen_params.sage. */
+#include "../fielddefines.h"
+
+#if defined(ENABLE_FIELD_BYTES_INT_4)
+
+#include "clmul_common_impl.h"
+
+#include "../int_utils.h"
+#include "../lintrans.h"
+#include "../sketch_impl.h"
+
+#endif
+
+#include "../sketch.h"
+
+namespace {
+#ifdef ENABLE_FIELD_INT_25
+// 25 bit field
+typedef RecLinTrans<uint32_t, 5, 5, 5, 5, 5> StatTable25;
+constexpr StatTable25 SQR_TABLE_25({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x12, 0x48, 0x120, 0x480, 0x1200, 0x4800, 0x12000, 0x48000, 0x120000, 0x480000, 0x1200000, 0x800012});
+constexpr StatTable25 SQR2_TABLE_25({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x48, 0x480, 0x4800, 0x48000, 0x480000, 0x800012, 0x104, 0x1040, 0x10400, 0x104000, 0x1040000, 0x400048, 0x492, 0x4920, 0x49200, 0x492000, 0x920012, 0x1200104});
+constexpr StatTable25 SQR4_TABLE_25({0x1, 0x10000, 0x480, 0x800012, 0x104000, 0x4920, 0x1200104, 0x1001000, 0x48048, 0x481040, 0x410448, 0x492492, 0x930002, 0x580, 0x1800012, 0x14c000, 0x5960, 0x160014c, 0x1493000, 0x58058, 0x5814c0, 0xc14c5a, 0x596596, 0x1974922, 0x1249684});
+constexpr StatTable25 SQR8_TABLE_25({0x1, 0x5960, 0x1411448, 0x1860922, 0x1d814d2, 0x1cdede8, 0x1e15e16, 0x1b79686, 0xfdf116, 0x1efe4c8, 0x1b839a8, 0x10ced66, 0xae05ce, 0x1459400, 0xa29fa6, 0x85e4d2, 0x7eecee, 0x183a96, 0x1eb2fa8, 0xede876, 0xf6e440, 0x1f7140a, 0xd07d7c, 0x10e4ea2, 0x1222a54});
+constexpr StatTable25 QRT_TABLE_25({0, 0x482110, 0x482112, 0x1b3c3e6, 0x482116, 0x4960ae, 0x1b3c3ee, 0x4088, 0x482106, 0x58a726, 0x49608e, 0x5ce52e, 0x1b3c3ae, 0x2006, 0x4008, 0x1c1a8, 0x482006, 0x1e96488, 0x58a526, 0x400000, 0x49648e, 0x1800006, 0x5ced2e, 0xb3d3a8, 0x1b3d3ae});
+typedef Field<uint32_t, 25, 9, StatTable25, &SQR_TABLE_25, &SQR2_TABLE_25, &SQR4_TABLE_25, &SQR8_TABLE_25, &QRT_TABLE_25, &QRT_TABLE_25, IdTrans, &ID_TRANS, &ID_TRANS> Field25;
+typedef FieldTri<uint32_t, 25, 3, RecLinTrans<uint32_t, 5, 5, 5, 5, 5>, &SQR_TABLE_25, &SQR2_TABLE_25, &SQR4_TABLE_25, &SQR8_TABLE_25, &QRT_TABLE_25, &QRT_TABLE_25, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri25;
+#endif
+
+#ifdef ENABLE_FIELD_INT_26
+// 26 bit field
+typedef RecLinTrans<uint32_t, 6, 5, 5, 5, 5> StatTable26;
+constexpr StatTable26 SQR_TABLE_26({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x1b, 0x6c, 0x1b0, 0x6c0, 0x1b00, 0x6c00, 0x1b000, 0x6c000, 0x1b0000, 0x6c0000, 0x1b00000, 0x2c0001b, 0x300005a});
+constexpr StatTable26 SQR2_TABLE_26({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x6c, 0x6c0, 0x6c00, 0x6c000, 0x6c0000, 0x2c0001b, 0x145, 0x1450, 0x14500, 0x145000, 0x1450000, 0x500077, 0x100076b, 0x76dc, 0x76dc0, 0x76dc00, 0x36dc01b, 0x2dc011f, 0x1c01105});
+constexpr StatTable26 SQR4_TABLE_26({0x1, 0x10000, 0x6c0, 0x2c0001b, 0x145000, 0x76dc, 0x2dc011f, 0x1101100, 0x106ac6c, 0x6ad515, 0x1145127, 0x121b6dc, 0x2da1d0f, 0x10007c1, 0x3c7c01b, 0x128290, 0x29062e0, 0x2ee8d68, 0x167abcd, 0x3cabbce, 0x3c7a862, 0x6b83ce, 0x3cf5620, 0x229b787, 0x38a6b0f, 0x3071ade});
+constexpr StatTable26 SQR8_TABLE_26({0x1, 0x29062e0, 0x2b2942d, 0x34ab63, 0x3bddebb, 0x7b1823, 0x58b9ae, 0x391720e, 0x1385e18, 0x3891746, 0x13069c5, 0x2dfd089, 0x12a35ff, 0x3e534f, 0x172c6a2, 0x55338f, 0x3887137, 0x3f45b03, 0x164a695, 0x2c7e7ef, 0x29c907d, 0x636c85, 0x3db4007, 0x97e7ff, 0x3cbfe55, 0x31c0d96});
+constexpr StatTable26 QRT_TABLE_26({0x217b530, 0x2ae82a8, 0x2ae82aa, 0x2001046, 0x2ae82ae, 0x2de032e, 0x200104e, 0x70c10c, 0x2ae82be, 0x20151f2, 0x2de030e, 0xbc1400, 0x200100e, 0x178570, 0x70c18c, 0x2ae4232, 0x2ae83be, 0x211d742, 0x20153f2, 0x21f54f2, 0x2de070e, 0x5e0700, 0xbc1c00, 0x3abb97e, 0x200000e, 0});
+typedef Field<uint32_t, 26, 27, StatTable26, &SQR_TABLE_26, &SQR2_TABLE_26, &SQR4_TABLE_26, &SQR8_TABLE_26, &QRT_TABLE_26, &QRT_TABLE_26, IdTrans, &ID_TRANS, &ID_TRANS> Field26;
+#endif
+
+#ifdef ENABLE_FIELD_INT_27
+// 27 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 5, 5, 5> StatTable27;
+constexpr StatTable27 SQR_TABLE_27({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x4e, 0x138, 0x4e0, 0x1380, 0x4e00, 0x13800, 0x4e000, 0x138000, 0x4e0000, 0x1380000, 0x4e00000, 0x380004e, 0x600011f});
+constexpr StatTable27 SQR2_TABLE_27({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x4e, 0x4e0, 0x4e00, 0x4e000, 0x4e0000, 0x4e00000, 0x600011f, 0x1054, 0x10540, 0x105400, 0x1054000, 0x54004e, 0x54004e0, 0x4004f76, 0x4f658, 0x4f6580, 0x4f65800, 0x765811f, 0x658101a, 0x5810004});
+constexpr StatTable27 SQR4_TABLE_27({0x1, 0x10000, 0x4e0, 0x4e00000, 0x105400, 0x4004f76, 0x765811f, 0x1001110, 0x114e04e, 0x4abe54, 0x6551445, 0x45e212e, 0x13ccbdc, 0x3d805ef, 0x5e10100, 0x114b0e0, 0xe4bf22, 0x721c505, 0x51b3ba8, 0x3bf04d5, 0x4dabba0, 0x3b0aa45, 0x24a80cb, 0xc3d4b0, 0x4b34626, 0x6372e18, 0x6028c1b});
+constexpr StatTable27 SQR8_TABLE_27({0x1, 0xe4bf22, 0x430cb3c, 0x73b7225, 0x6526539, 0x3c278e3, 0x4724a6e, 0x48b39b4, 0x1dbf7de, 0x106508, 0x3564785, 0x33ae33f, 0x61d6685, 0x6adaca3, 0x2786b6f, 0x4e76784, 0x869f42, 0x466b048, 0x415e00e, 0x46c3c9a, 0x73ffd91, 0x49002e0, 0x3734fed, 0x3c04a43, 0x191d3ee, 0xe828b9, 0xfab68c});
+constexpr StatTable27 QRT_TABLE_27({0x6bf0530, 0x2be4496, 0x2be4494, 0x2bf0522, 0x2be4490, 0x1896cca, 0x2bf052a, 0x408a, 0x2be4480, 0x368ae72, 0x1896cea, 0x18d2ee0, 0x2bf056a, 0x1c76d6a, 0x400a, 0x336e9f8, 0x2be4580, 0x36baf12, 0x368ac72, 0x430360, 0x18968ea, 0x34a6b80, 0x18d26e0, 0xbf1560, 0x2bf156a, 0, 0x1c74d6a});
+typedef Field<uint32_t, 27, 39, StatTable27, &SQR_TABLE_27, &SQR2_TABLE_27, &SQR4_TABLE_27, &SQR8_TABLE_27, &QRT_TABLE_27, &QRT_TABLE_27, IdTrans, &ID_TRANS, &ID_TRANS> Field27;
+#endif
+
+#ifdef ENABLE_FIELD_INT_28
+// 28 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 6, 5, 5> StatTableTRI28;
+constexpr StatTableTRI28 SQR_TABLE_TRI28({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x3, 0xc, 0x30, 0xc0, 0x300, 0xc00, 0x3000, 0xc000, 0x30000, 0xc0000, 0x300000, 0xc00000, 0x3000000, 0xc000000});
+constexpr StatTableTRI28 SQR2_TABLE_TRI28({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x3, 0x30, 0x300, 0x3000, 0x30000, 0x300000, 0x3000000, 0x5, 0x50, 0x500, 0x5000, 0x50000, 0x500000, 0x5000000, 0xf, 0xf0, 0xf00, 0xf000, 0xf0000, 0xf00000, 0xf000000});
+constexpr StatTableTRI28 SQR4_TABLE_TRI28({0x1, 0x10000, 0x30, 0x300000, 0x500, 0x5000000, 0xf000, 0x11, 0x110000, 0x330, 0x3300000, 0x5500, 0x500000f, 0xff000, 0x101, 0x1010000, 0x3030, 0x300005, 0x50500, 0x50000f0, 0xf0f000, 0x1111, 0x1110003, 0x33330, 0x3300055, 0x555500, 0x5000fff, 0xffff000});
+constexpr StatTableTRI28 SQR8_TABLE_TRI28({0x1, 0x3030, 0x5000500, 0xf0e111, 0x3210000, 0x6300faa, 0x40ef10e, 0x501, 0xf0c030, 0x5110630, 0x395b444, 0x621010e, 0x6010f9b, 0x13bc4cb, 0x110001, 0x3303065, 0xff50f, 0xf0e120, 0x3243530, 0x330fabb, 0x5ec232c, 0x511050e, 0x3c1c064, 0x2ec60a, 0x3954175, 0x7c5c43d, 0x20acba, 0x943bc43});
+constexpr StatTableTRI28 QRT_TABLE_TRI28({0x121d57a, 0x40216, 0x40214, 0x8112578, 0x40210, 0x10110, 0x8112570, 0x12597ec, 0x40200, 0x6983e00, 0x10130, 0x972b99c, 0x8112530, 0x8002000, 0x125976c, 0x815a76c, 0x40300, 0x936b29c, 0x6983c00, 0x97bb8ac, 0x10530, 0x9103000, 0x972b19c, 0xf6384ac, 0x8113530, 0x4113530, 0x8000000, 0});
+typedef FieldTri<uint32_t, 28, 1, StatTableTRI28, &SQR_TABLE_TRI28, &SQR2_TABLE_TRI28, &SQR4_TABLE_TRI28, &SQR8_TABLE_TRI28, &QRT_TABLE_TRI28, &QRT_TABLE_TRI28, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri28;
+#endif
+
+#ifdef ENABLE_FIELD_INT_29
+// 29 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 6, 6, 5> StatTable29;
+constexpr StatTable29 SQR_TABLE_29({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0xa, 0x28, 0xa0, 0x280, 0xa00, 0x2800, 0xa000, 0x28000, 0xa0000, 0x280000, 0xa00000, 0x2800000, 0xa000000, 0x8000005});
+constexpr StatTable29 SQR2_TABLE_29({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x28, 0x280, 0x2800, 0x28000, 0x280000, 0x2800000, 0x8000005, 0x44, 0x440, 0x4400, 0x44000, 0x440000, 0x4400000, 0x400000a, 0xaa, 0xaa0, 0xaa00, 0xaa000, 0xaa0000, 0xaa00000, 0xa000011});
+constexpr StatTable29 SQR4_TABLE_29({0x1, 0x10000, 0x28, 0x280000, 0x440, 0x4400000, 0xaa00, 0xa000011, 0x101000, 0x10000280, 0x2828000, 0x4444, 0x444000a, 0xaaaa0, 0xaa00101, 0x1000100, 0x1002800, 0x8002805, 0x8044005, 0x440aa, 0xaa00aa, 0xaa1010, 0x10101010, 0x10128280, 0x28282c4, 0x2c44444, 0x4444eaa, 0xeaaaaaa, 0xaaba001});
+constexpr StatTable29 SQR8_TABLE_29({0x1, 0x1002800, 0x4680000, 0xae50ba, 0x2822a00, 0x14545eba, 0x110aed64, 0xc6eeaaf, 0x4ee00a0, 0x10aba290, 0x1bd6efc1, 0x8222b29, 0x1c791ebf, 0x174e85da, 0x1cc66c7f, 0x29292c4, 0x2886c20, 0xea04467, 0xc0eeb87, 0xccd4115, 0x16d5fa2e, 0x1cf8fe75, 0xe45a4e1, 0x19018b3f, 0x1d64778, 0x2e0bdf8, 0xa1bd96b, 0xff5b70e, 0x14d89770});
+constexpr StatTable29 QRT_TABLE_29({0x1b8351dc, 0xb87135e, 0xb87135c, 0xda7b35e, 0xb871358, 0x621a116, 0xda7b356, 0x40200, 0xb871348, 0xc9e2620, 0x621a136, 0x478b16, 0xda7b316, 0x6762e20, 0x40280, 0x6202000, 0xb871248, 0x627a316, 0xc9e2420, 0xcd1ad36, 0x621a536, 0x760e20, 0x478316, 0xa760e20, 0xda7a316, 0x8000000, 0x6760e20, 0, 0x44280});
+typedef Field<uint32_t, 29, 5, StatTable29, &SQR_TABLE_29, &SQR2_TABLE_29, &SQR4_TABLE_29, &SQR8_TABLE_29, &QRT_TABLE_29, &QRT_TABLE_29, IdTrans, &ID_TRANS, &ID_TRANS> Field29;
+typedef FieldTri<uint32_t, 29, 2, RecLinTrans<uint32_t, 6, 6, 6, 6, 5>, &SQR_TABLE_29, &SQR2_TABLE_29, &SQR4_TABLE_29, &SQR8_TABLE_29, &QRT_TABLE_29, &QRT_TABLE_29, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri29;
+#endif
+
+#ifdef ENABLE_FIELD_INT_30
+// 30 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 6, 6, 6> StatTableTRI30;
+constexpr StatTableTRI30 SQR_TABLE_TRI30({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x3, 0xc, 0x30, 0xc0, 0x300, 0xc00, 0x3000, 0xc000, 0x30000, 0xc0000, 0x300000, 0xc00000, 0x3000000, 0xc000000, 0x30000000});
+constexpr StatTableTRI30 SQR2_TABLE_TRI30({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0xc, 0xc0, 0xc00, 0xc000, 0xc0000, 0xc00000, 0xc000000, 0x5, 0x50, 0x500, 0x5000, 0x50000, 0x500000, 0x5000000, 0x10000003, 0x3c, 0x3c0, 0x3c00, 0x3c000, 0x3c0000, 0x3c00000, 0x3c000000});
+constexpr StatTableTRI30 SQR4_TABLE_TRI30({0x1, 0x10000, 0xc, 0xc0000, 0x50, 0x500000, 0x3c0, 0x3c00000, 0x1100, 0x11000000, 0xcc00, 0xc000005, 0x55000, 0x1000003f, 0x3fc000, 0x101, 0x1010000, 0xc0c, 0xc0c0000, 0x5050, 0x10500003, 0x3c3c0, 0x3c00011, 0x111100, 0x110000cc, 0xcccc00, 0xc000555, 0x5555000, 0x10003fff, 0x3fffc000});
+constexpr StatTableTRI30 SQR8_TABLE_TRI30({0x1, 0x1010000, 0xc000c, 0xc0c5050, 0x390, 0x13900012, 0x12c012c0, 0x121ddddd, 0x54100, 0x1003f33, 0xc3f0d04, 0x9555558, 0xd379000, 0x105d3fa2, 0x1d615e9e, 0x1101, 0x100100cc, 0xc0ccc09, 0x5590505, 0x3a9390, 0x3913fec, 0x13fedfcd, 0x121ddd8c, 0x11544103, 0x2cc3cff, 0x3e24c45, 0x9558bc8, 0x3a7958b, 0x1e98b158, 0x29d629e9});
+constexpr StatTableTRI30 QRT_TABLE_TRI30({0x2159df4a, 0x109134a, 0x1091348, 0x10114, 0x109134c, 0x3a203420, 0x1011c, 0x20004080, 0x109135c, 0x2005439c, 0x3a203400, 0x100400, 0x1015c, 0x3eb21930, 0x20004000, 0x20504c00, 0x109125c, 0x3b2b276c, 0x2005419c, 0x210450c0, 0x3a203000, 0x3e93186c, 0x100c00, 0x3aa23530, 0x1115c, 0x6b3286c, 0x3eb23930, 0xeb23930, 0x20000000, 0});
+typedef FieldTri<uint32_t, 30, 1, StatTableTRI30, &SQR_TABLE_TRI30, &SQR2_TABLE_TRI30, &SQR4_TABLE_TRI30, &SQR8_TABLE_TRI30, &QRT_TABLE_TRI30, &QRT_TABLE_TRI30, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri30;
+#endif
+
+#ifdef ENABLE_FIELD_INT_31
+// 31 bit field
+typedef RecLinTrans<uint32_t, 6, 5, 5, 5, 5, 5> StatTable31;
+constexpr StatTable31 SQR_TABLE_31({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x12, 0x48, 0x120, 0x480, 0x1200, 0x4800, 0x12000, 0x48000, 0x120000, 0x480000, 0x1200000, 0x4800000, 0x12000000, 0x48000000, 0x20000012});
+constexpr StatTable31 SQR2_TABLE_31({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x12, 0x120, 0x1200, 0x12000, 0x120000, 0x1200000, 0x12000000, 0x20000012, 0x104, 0x1040, 0x10400, 0x104000, 0x1040000, 0x10400000, 0x4000012, 0x40000120, 0x1248, 0x12480, 0x124800, 0x1248000, 0x12480000, 0x24800012, 0x48000104});
+constexpr StatTable31 SQR4_TABLE_31({0x1, 0x10000, 0x12, 0x120000, 0x104, 0x1040000, 0x1248, 0x12480000, 0x10010, 0x100012, 0x120120, 0x1200104, 0x1041040, 0x10401248, 0x12492480, 0x24810002, 0x112, 0x1120000, 0x1304, 0x13040000, 0x11648, 0x16480012, 0x134810, 0x48100116, 0x1121120, 0x11201304, 0x13053040, 0x3041165a, 0x16596492, 0x64934922, 0x49248016});
+constexpr StatTable31 SQR8_TABLE_31({0x1, 0x112, 0x10104, 0x1131648, 0x10002, 0x1120224, 0x106021a, 0x146e3f86, 0x16, 0x174c, 0x161658, 0x175b1130, 0x16002c, 0x174c2e98, 0x16742dfc, 0x3f877966, 0x114, 0x10768, 0x1151050, 0x66b75b2, 0x1140228, 0x76a0ec2, 0x127a33da, 0x79648102, 0x1738, 0x1665f0, 0x172f64e0, 0x73cc668c, 0x17382e70, 0x65dccaac, 0x4abf956e});
+constexpr StatTable31 QRT_TABLE_31({0, 0x10110, 0x10112, 0x15076e, 0x10116, 0x117130e, 0x150766, 0x4743fa0, 0x10106, 0x1121008, 0x117132e, 0x176b248e, 0x150726, 0x172a2c88, 0x4743f20, 0x7eb81e86, 0x10006, 0x20008, 0x1121208, 0x56b2c8e, 0x117172e, 0x133f1bae, 0x176b2c8e, 0x7f2a0c8e, 0x151726, 0x10000000, 0x172a0c88, 0x60000006, 0x4747f20, 0x3eb89e80, 0x7eb89e86});
+typedef Field<uint32_t, 31, 9, StatTable31, &SQR_TABLE_31, &SQR2_TABLE_31, &SQR4_TABLE_31, &SQR8_TABLE_31, &QRT_TABLE_31, &QRT_TABLE_31, IdTrans, &ID_TRANS, &ID_TRANS> Field31;
+typedef FieldTri<uint32_t, 31, 3, RecLinTrans<uint32_t, 6, 5, 5, 5, 5, 5>, &SQR_TABLE_31, &SQR2_TABLE_31, &SQR4_TABLE_31, &SQR8_TABLE_31, &QRT_TABLE_31, &QRT_TABLE_31, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri31;
+#endif
+
+#ifdef ENABLE_FIELD_INT_32
+// 32 bit field
+typedef RecLinTrans<uint32_t, 6, 6, 5, 5, 5, 5> StatTable32;
+constexpr StatTable32 SQR_TABLE_32({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x8d, 0x234, 0x8d0, 0x2340, 0x8d00, 0x23400, 0x8d000, 0x234000, 0x8d0000, 0x2340000, 0x8d00000, 0x23400000, 0x8d000000, 0x3400011a, 0xd0000468, 0x40001037});
+constexpr StatTable32 SQR2_TABLE_32({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x8d, 0x8d0, 0x8d00, 0x8d000, 0x8d0000, 0x8d00000, 0x8d000000, 0xd0000468, 0x4051, 0x40510, 0x405100, 0x4051000, 0x40510000, 0x5100234, 0x51002340, 0x100236b9, 0x236b1d, 0x236b1d0, 0x236b1d00, 0x36b1d11a, 0x6b1d1037, 0xb1d1005e, 0x1d10001f, 0xd100017d});
+constexpr StatTable32 SQR4_TABLE_32({0x1, 0x10000, 0x8d, 0x8d0000, 0x4051, 0x40510000, 0x236b1d, 0x6b1d1037, 0x10001101, 0x1109d000, 0xd00859e5, 0x59881468, 0x144737e8, 0x37e2c4e3, 0xc4f9a67a, 0xa61d8c55, 0x8c010001, 0x41dc8d, 0xdc8d23cd, 0x23a60c51, 0xc41630e, 0x63087fcd, 0x7ffe7368, 0x735580f6, 0x80cd8e29, 0x8e6fe311, 0xe350f32b, 0xf35edc90, 0xdced0bd6, 0xbbd3eb1, 0x3eb4a621, 0xa63f6bc4});
+constexpr StatTable32 SQR8_TABLE_32({0x1, 0x8c010001, 0x6b9010bb, 0x7faf6b, 0xc4da8d37, 0xc10ab646, 0x445f546c, 0xe389129e, 0xd8aa2d3e, 0x85249468, 0xd599253f, 0x458976f9, 0xc9c86411, 0xccc2f34b, 0xa79e37dc, 0x9068e3c4, 0x3a30447f, 0x674c3398, 0x94f38a7, 0x402d3532, 0x116fffc7, 0x1c6b5ba2, 0xcd6a32e4, 0x49067a77, 0xa7f6a61e, 0x3cc3746, 0xeebe962e, 0x599276e1, 0x7b5fa4d9, 0x2aa3ce1, 0x990f8767, 0x1c3b66cb});
+constexpr StatTable32 QRT_TABLE_32({0x54fd1264, 0xc26fcd64, 0xc26fcd66, 0x238a7462, 0xc26fcd62, 0x973bccaa, 0x238a746a, 0x77766712, 0xc26fcd72, 0xc1bdd556, 0x973bcc8a, 0x572a094c, 0x238a742a, 0xb693be84, 0x77766792, 0x9555c03e, 0xc26fcc72, 0x568419f8, 0xc1bdd756, 0x96c3d2ca, 0x973bc88a, 0x54861fdc, 0x572a014c, 0xb79badc4, 0x238a642a, 0xb9b99fe0, 0xb6939e84, 0xc519fa86, 0x77762792, 0, 0x9555403e, 0x377627ba});
+typedef Field<uint32_t, 32, 141, StatTable32, &SQR_TABLE_32, &SQR2_TABLE_32, &SQR4_TABLE_32, &SQR8_TABLE_32, &QRT_TABLE_32, &QRT_TABLE_32, IdTrans, &ID_TRANS, &ID_TRANS> Field32;
+#endif
+}
+
+Sketch* ConstructClMul4Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_25
+ case 25: return new SketchImpl<Field25>(implementation, 25);
+#endif
+#ifdef ENABLE_FIELD_INT_26
+ case 26: return new SketchImpl<Field26>(implementation, 26);
+#endif
+#ifdef ENABLE_FIELD_INT_27
+ case 27: return new SketchImpl<Field27>(implementation, 27);
+#endif
+#ifdef ENABLE_FIELD_INT_29
+ case 29: return new SketchImpl<Field29>(implementation, 29);
+#endif
+#ifdef ENABLE_FIELD_INT_31
+ case 31: return new SketchImpl<Field31>(implementation, 31);
+#endif
+#ifdef ENABLE_FIELD_INT_32
+ case 32: return new SketchImpl<Field32>(implementation, 32);
+#endif
+ }
+ return nullptr;
+}
+
+Sketch* ConstructClMulTri4Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_25
+ case 25: return new SketchImpl<FieldTri25>(implementation, 25);
+#endif
+#ifdef ENABLE_FIELD_INT_28
+ case 28: return new SketchImpl<FieldTri28>(implementation, 28);
+#endif
+#ifdef ENABLE_FIELD_INT_29
+ case 29: return new SketchImpl<FieldTri29>(implementation, 29);
+#endif
+#ifdef ENABLE_FIELD_INT_30
+ case 30: return new SketchImpl<FieldTri30>(implementation, 30);
+#endif
+#ifdef ENABLE_FIELD_INT_31
+ case 31: return new SketchImpl<FieldTri31>(implementation, 31);
+#endif
+ }
+ return nullptr;
+}
diff --git a/src/fields/clmul_5bytes.cpp b/src/fields/clmul_5bytes.cpp
new file mode 100644
index 00000000..29c3fb10
--- /dev/null
+++ b/src/fields/clmul_5bytes.cpp
@@ -0,0 +1,174 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* This file was substantially auto-generated by doc/gen_params.sage. */
+#include "../fielddefines.h"
+
+#if defined(ENABLE_FIELD_BYTES_INT_5)
+
+#include "clmul_common_impl.h"
+
+#include "../int_utils.h"
+#include "../lintrans.h"
+#include "../sketch_impl.h"
+
+#endif
+
+#include "../sketch.h"
+
+namespace {
+#ifdef ENABLE_FIELD_INT_33
+// 33 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 5, 5, 5> StatTable33;
+constexpr StatTable33 SQR_TABLE_33({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x802, 0x2008, 0x8020, 0x20080, 0x80200, 0x200800, 0x802000, 0x2008000, 0x8020000, 0x20080000, 0x80200000, 0x800401, 0x2001004, 0x8004010, 0x20010040, 0x80040100});
+constexpr StatTable33 SQR2_TABLE_33({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x2008, 0x20080, 0x200800, 0x2008000, 0x20080000, 0x800401, 0x8004010, 0x80040100, 0x400004, 0x4000040, 0x40000400, 0x4802, 0x48020, 0x480200, 0x4802000, 0x48020000, 0x80200802, 0x2009024, 0x20090240, 0x902001, 0x9020010, 0x90200100, 0x102000004, 0x20002048});
+constexpr StatTable33 SQR4_TABLE_33({0x1, 0x10000, 0x100000000, 0x2008000, 0x80040100, 0x4802, 0x48020000, 0x902001, 0x20002048, 0x20081000, 0x10400004, 0x248820, 0x88204812, 0x49020410, 0x4822081, 0x20880641, 0x6000044, 0x480300, 0x3009024, 0x90220180, 0xa00c11, 0xc104050, 0x40482608, 0x2688b024, 0xb0690344, 0x102248834, 0x8a30c912, 0xc8062518, 0x24886803, 0x684a0244, 0x294a025, 0xa020294a, 0x280a1010});
+constexpr StatTable33 SQR8_TABLE_33({0x1, 0x6000044, 0x280a1010, 0x122ac8e75, 0x83209926, 0x4a7a8a1, 0xcada863d, 0x6f2ab824, 0x6b4a8654, 0x70484bd6, 0x164c04e0b, 0x2fbc1617, 0xe095e5a3, 0xeaf7847d, 0xe5625e26, 0xa6aaa3e5, 0xc0164126, 0xd06217c0, 0x1ae58d21, 0xa8600250, 0xbaf87951, 0x8e12c19a, 0xa9b413b9, 0xb75ef087, 0x17e9214d9, 0x85968f33, 0x1e299478f, 0x92bc9a0f, 0x1975d642, 0x11af0b3f1, 0x4e86ee77, 0xe75f4726, 0x38026cce});
+constexpr StatTable33 SQR16_TABLE_33({0x1, 0x185df5e91, 0x193fb40eb, 0xd464f9e4, 0x1ba2d73a6, 0x1d9288c5e, 0x5de03a49, 0x1869ea37b, 0x13faaf379, 0x195d1a8f5, 0x6afd5625, 0xf9d75bab, 0xaf44fe50, 0x101034b9e, 0xcc889caf, 0x5ec7455, 0x7d232a66, 0x17dcfe2c3, 0x1c66ff8d0, 0x17107e836, 0x1939cdead, 0x9852afa0, 0x1b946909a, 0x1846638c5, 0xdd5fa94c, 0x1cb2600fe, 0x19241c856, 0x15fe05ccd, 0xc9f9a425, 0x89e0f463, 0x37b01b39, 0xab0410e0, 0x1ace4ca03});
+constexpr StatTable33 QRT_TABLE_33({0xba504dd4, 0x1e2798ef2, 0x1e2798ef0, 0x6698a4ec, 0x1e2798ef4, 0x1c7f1bef0, 0x6698a4e4, 0x16da1b384, 0x1e2798ee4, 0x661ca6ec, 0x1c7f1bed0, 0x1483b87a6, 0x6698a4a4, 0x800000, 0x16da1b304, 0x1a185101c, 0x1e2798fe4, 0xaa400954, 0x661ca4ec, 0x667caeec, 0x1c7f1bad0, 0x400800, 0x1483b8fa6, 0, 0x6698b4a4, 0x1c61da4b8, 0x802000, 0x16e5dadec, 0x16da1f304, 0x62fc8eec, 0x1a185901c, 0x1661da5ec, 0x1e2788fe4});
+typedef Field<uint64_t, 33, 1025, StatTable33, &SQR_TABLE_33, &SQR2_TABLE_33, &SQR4_TABLE_33, &SQR8_TABLE_33, &SQR16_TABLE_33, &QRT_TABLE_33, IdTrans, &ID_TRANS, &ID_TRANS> Field33;
+typedef FieldTri<uint64_t, 33, 10, RecLinTrans<uint64_t, 6, 6, 6, 5, 5, 5>, &SQR_TABLE_33, &SQR2_TABLE_33, &SQR4_TABLE_33, &SQR8_TABLE_33, &SQR16_TABLE_33, &QRT_TABLE_33, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri33;
+#endif
+
+#ifdef ENABLE_FIELD_INT_34
+// 34 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 5, 5> StatTable34;
+constexpr StatTable34 SQR_TABLE_34({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x81, 0x204, 0x810, 0x2040, 0x8100, 0x20400, 0x81000, 0x204000, 0x810000, 0x2040000, 0x8100000, 0x20400000, 0x81000000, 0x204000000, 0x10000102, 0x40000408, 0x100001020});
+constexpr StatTable34 SQR2_TABLE_34({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x204, 0x2040, 0x20400, 0x204000, 0x2040000, 0x20400000, 0x204000000, 0x40000408, 0x4001, 0x40010, 0x400100, 0x4001000, 0x40010000, 0x100081, 0x1000810, 0x10008100, 0x100081000, 0x810204, 0x8102040, 0x81020400, 0x10204102, 0x102041020, 0x20410004, 0x204100040, 0x41000008});
+constexpr StatTable34 SQR4_TABLE_34({0x1, 0x10000, 0x100000000, 0x204000, 0x40000408, 0x4001000, 0x10008100, 0x81020400, 0x204100040, 0x304, 0x3040000, 0x6041, 0x60410000, 0x1000c1010, 0x10304183, 0x4181020c, 0x102042060, 0x20400001, 0x50010, 0x100100081, 0xa14204, 0x142041428, 0x14001001, 0x10038500, 0x385020400, 0x204704140, 0x41000f1c, 0xf143040, 0x3041e145, 0x1e1430410, 0x3042c5050, 0x5030448b, 0x4481120c, 0x112048120});
+constexpr StatTable34 SQR8_TABLE_34({0x1, 0x102042060, 0x4481120c, 0x1523455ab, 0x307081050, 0x21410f1c, 0x275d0e309, 0x3f676408a, 0x143a54d38, 0x304100344, 0x181774550, 0x1003cd092, 0x3f36b6421, 0x164d51695, 0x3e7c7f2ab, 0x9309b234, 0x354f8d24c, 0x1f5431410, 0x142012478, 0xc5225409, 0x14033f3cf, 0x123bd530c, 0x1100ee58, 0x35490c368, 0x2e1f3dcba, 0x2018108d2, 0x3c61a735d, 0xbf8fa918, 0x282ab07ea, 0x19c32af, 0x175e54c02, 0x2e4dfe2bb, 0x3374ab928, 0x3124a055});
+constexpr StatTable34 SQR16_TABLE_34({0x1, 0x3448e6f02, 0x352590eb9, 0xb173da17, 0x264977d39, 0x172d45e48, 0x1e026e5d6, 0x357b54017, 0x2925d27a4, 0x1f6a32696, 0x2f49f220c, 0x3a7383d9e, 0x28111d79b, 0x5580fcf1, 0x276ede679, 0x175b379f8, 0x34d67b66, 0xc7019416, 0x3f3d9d59f, 0x2a7c2c032, 0x2b3482ba7, 0x177cd0128, 0x1d6f4bd2e, 0x31647a632, 0x41353027, 0x56292eea, 0x2733c0501, 0x6d7ed066, 0x2f3db9a75, 0x3225bc5cc, 0x3f22da089, 0xd0a7588e, 0xb60b22d1, 0xc2fddb7e});
+constexpr StatTable34 QRT_TABLE_34({0x2f973a1f6, 0x40202, 0x40200, 0x348102060, 0x40204, 0x8000420, 0x348102068, 0x1092195c8, 0x40214, 0x3f6881b6e, 0x8000400, 0x3f810383e, 0x348102028, 0x340002068, 0x109219548, 0x24015a774, 0x40314, 0x3f050343e, 0x3f688196e, 0x3f81c3a3a, 0x8000000, 0x24031a560, 0x3f810303e, 0xb08c1a12, 0x348103028, 0xb2881906, 0x340000068, 0, 0x10921d548, 0x2e131e576, 0x240152774, 0x18921d55e, 0x50314, 0x14015271c});
+typedef Field<uint64_t, 34, 129, StatTable34, &SQR_TABLE_34, &SQR2_TABLE_34, &SQR4_TABLE_34, &SQR8_TABLE_34, &SQR16_TABLE_34, &QRT_TABLE_34, IdTrans, &ID_TRANS, &ID_TRANS> Field34;
+typedef FieldTri<uint64_t, 34, 7, RecLinTrans<uint64_t, 6, 6, 6, 6, 5, 5>, &SQR_TABLE_34, &SQR2_TABLE_34, &SQR4_TABLE_34, &SQR8_TABLE_34, &SQR16_TABLE_34, &QRT_TABLE_34, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri34;
+#endif
+
+#ifdef ENABLE_FIELD_INT_35
+// 35 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 5> StatTable35;
+constexpr StatTable35 SQR_TABLE_35({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0xa, 0x28, 0xa0, 0x280, 0xa00, 0x2800, 0xa000, 0x28000, 0xa0000, 0x280000, 0xa00000, 0x2800000, 0xa000000, 0x28000000, 0xa0000000, 0x280000000, 0x200000005});
+constexpr StatTable35 SQR2_TABLE_35({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0xa, 0xa0, 0xa00, 0xa000, 0xa0000, 0xa00000, 0xa000000, 0xa0000000, 0x200000005, 0x44, 0x440, 0x4400, 0x44000, 0x440000, 0x4400000, 0x44000000, 0x440000000, 0x400000028, 0x2a8, 0x2a80, 0x2a800, 0x2a8000, 0x2a80000, 0x2a800000, 0x2a8000000, 0x280000011});
+constexpr StatTable35 SQR4_TABLE_35({0x1, 0x10000, 0x100000000, 0xa000, 0xa0000000, 0x4400, 0x44000000, 0x2a80, 0x2a800000, 0x1010, 0x10100000, 0xa0a, 0xa0a0000, 0x200000445, 0x4444000, 0x4400002a8, 0x2aaa800, 0x2a8000101, 0x1000100, 0x10000a0, 0xa000a0, 0xa00044, 0x440044, 0x400440028, 0x4002a8028, 0x2802a8011, 0x280101011, 0x1010100a, 0x100a0a0a, 0x20a0a0a05, 0x20a044445, 0x444444440, 0x44442aaa8, 0x2aaaaaaa8, 0x2aaa90001});
+constexpr StatTable35 SQR8_TABLE_35({0x1, 0x2aaa800, 0x44442aaa8, 0x6400006ed, 0x64e4e4e45, 0x14544000, 0x8a145454, 0x2000034df, 0x49a749a36, 0xaa0a0000, 0x10aa0aaa, 0x1ba1a, 0x393a91ba, 0x3febaaaa9, 0x285105155, 0xa0ad9ad4, 0x269ce8d3b, 0x4de74f4e6, 0x42aaa8028, 0x4002aeea8, 0x400e46eec, 0x544e4006c, 0x145440144, 0x2abede545, 0x44309e74c, 0xa74eeda4, 0x64444ee49, 0x1aa1aaaa, 0x2b90bb1b1, 0x393902109, 0x16bc47bb2, 0x271ad1511, 0x6c8f98767, 0x69d3aa74c, 0x27790dc3b});
+constexpr StatTable35 SQR16_TABLE_35({0x1, 0x4c80f98a4, 0x763684437, 0x5a1cc86a0, 0x38922db8, 0x71755e12d, 0x2ca94c627, 0x388a2bc7f, 0x406596de0, 0x1818c6958, 0x174a92efe, 0x1a80c764e, 0x2f23eacbf, 0xd611ea8, 0x64d783fd5, 0x4fdfe0798, 0x31459de8d, 0x62c889d99, 0x9c419962, 0x2d8d865b3, 0x1ac7e7ffc, 0x38a0c12f3, 0x9fbc1076, 0x6f76d3b89, 0x6e472c757, 0x5f240de42, 0x10176ecc0, 0x20c1cef8, 0x8f77f91c, 0x3f6e533b9, 0x62017c147, 0x5ce81e2fa, 0x371fe4ad9, 0x2552b5046, 0xc3f3696c});
+constexpr StatTable35 QRT_TABLE_35({0x5c2038114, 0x2bf547ee8, 0x2bf547eea, 0x2bf1074e8, 0x2bf547eee, 0x1883d0736, 0x2bf1074e0, 0x100420, 0x2bf547efe, 0x400800, 0x1883d0716, 0x5e90e4a0, 0x2bf1074a0, 0x4e70ac20, 0x1004a0, 0x2f060c880, 0x2bf547ffe, 0x37d55fffe, 0x400a00, 0x3372573de, 0x1883d0316, 0x700c20, 0x5e90eca0, 0x10604880, 0x2bf1064a0, 0x18f35377e, 0x4e708c20, 0x33f557ffe, 0x1044a0, 0x1bf557ffe, 0x2f0604880, 0x200000000, 0x2bf557ffe, 0, 0x37d57fffe});
+typedef Field<uint64_t, 35, 5, StatTable35, &SQR_TABLE_35, &SQR2_TABLE_35, &SQR4_TABLE_35, &SQR8_TABLE_35, &SQR16_TABLE_35, &QRT_TABLE_35, IdTrans, &ID_TRANS, &ID_TRANS> Field35;
+typedef FieldTri<uint64_t, 35, 2, RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 5>, &SQR_TABLE_35, &SQR2_TABLE_35, &SQR4_TABLE_35, &SQR8_TABLE_35, &SQR16_TABLE_35, &QRT_TABLE_35, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri35;
+#endif
+
+#ifdef ENABLE_FIELD_INT_36
+// 36 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 6> StatTable36;
+constexpr StatTable36 SQR_TABLE_36({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x201, 0x804, 0x2010, 0x8040, 0x20100, 0x80400, 0x201000, 0x804000, 0x2010000, 0x8040000, 0x20100000, 0x80400000, 0x201000000, 0x804000000, 0x10000402, 0x40001008, 0x100004020, 0x400010080});
+constexpr StatTable36 SQR2_TABLE_36({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x201, 0x2010, 0x20100, 0x201000, 0x2010000, 0x20100000, 0x201000000, 0x10000402, 0x100004020, 0x40001, 0x400010, 0x4000100, 0x40001000, 0x400010000, 0x100804, 0x1008040, 0x10080400, 0x100804000, 0x8040201, 0x80402010, 0x804020100, 0x40200008, 0x402000080, 0x20000004, 0x200000040, 0x2, 0x20});
+constexpr StatTable36 SQR4_TABLE_36({0x1, 0x10000, 0x100000000, 0x201000, 0x10000402, 0x4000100, 0x1008040, 0x80402010, 0x20000004, 0x200, 0x2000000, 0x4020, 0x40200000, 0x80002, 0x800020000, 0x201008000, 0x80400010, 0x4, 0x40000, 0x400000000, 0x804000, 0x40001008, 0x10000400, 0x4020100, 0x201008040, 0x80000010, 0x800, 0x8000000, 0x10080, 0x100800000, 0x200008, 0x80402, 0x804020000, 0x201000040, 0x10, 0x100000});
+constexpr StatTable36 SQR8_TABLE_36({0x1, 0x80400010, 0x804020000, 0x201008, 0x2000080, 0x20000804, 0x1008000, 0x402, 0x800000, 0x200, 0x80000010, 0x804020100, 0x40201000, 0x400010000, 0x100004, 0x201000000, 0x80400, 0x100000000, 0x40000, 0x10, 0x804000100, 0x40201008, 0x2010080, 0x20000800, 0x200008040, 0x10080000, 0x4020, 0x8000000, 0x2000, 0x800000100, 0x40200008, 0x402010000, 0x100804, 0x1000040, 0x10000402, 0x804000});
+constexpr StatTable36 SQR16_TABLE_36({0x1, 0x402000000, 0x100800020, 0x201000, 0x10080402, 0x800000000, 0x1008040, 0x400000, 0x20000800, 0x200, 0x400010080, 0x100000020, 0x40200000, 0x10080002, 0x20100, 0x201008000, 0x80000000, 0x100804, 0x40000, 0x2000080, 0x20, 0x40001008, 0x10000002, 0x4020000, 0x201008040, 0x2010, 0x20100800, 0x8000000, 0x400010000, 0x4000, 0x200008, 0x2, 0x804000000, 0x201000040, 0x402000, 0x20100804});
+constexpr StatTable36 QRT_TABLE_36({0x40200, 0x8b0526186, 0x8b0526184, 0x240001000, 0x8b0526180, 0xcb6894d94, 0x240001008, 0xdb6880c22, 0x8b0526190, 0x8000200, 0xcb6894db4, 0x500424836, 0x240001048, 0x406cb2834, 0xdb6880ca2, 0x241200008, 0x8b0526090, 0xdb05021a6, 0x8000000, 0xdb01829b2, 0xcb68949b4, 0x1001000, 0x500424036, 0x106116406, 0x240000048, 0xcb29968a4, 0x406cb0834, 0, 0xdb6884ca2, 0x110010516, 0x241208008, 0x430434520, 0x8b0536090, 0x41208040, 0xdb05221a6, 0xb6884d14});
+typedef Field<uint64_t, 36, 513, StatTable36, &SQR_TABLE_36, &SQR2_TABLE_36, &SQR4_TABLE_36, &SQR8_TABLE_36, &SQR16_TABLE_36, &QRT_TABLE_36, IdTrans, &ID_TRANS, &ID_TRANS> Field36;
+typedef FieldTri<uint64_t, 36, 9, RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 6>, &SQR_TABLE_36, &SQR2_TABLE_36, &SQR4_TABLE_36, &SQR8_TABLE_36, &SQR16_TABLE_36, &QRT_TABLE_36, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri36;
+#endif
+
+#ifdef ENABLE_FIELD_INT_37
+// 37 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 5, 5, 5, 5, 5> StatTable37;
+constexpr StatTable37 SQR_TABLE_37({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x1000000000, 0xa6, 0x298, 0xa60, 0x2980, 0xa600, 0x29800, 0xa6000, 0x298000, 0xa60000, 0x2980000, 0xa600000, 0x29800000, 0xa6000000, 0x298000000, 0xa60000000, 0x980000053, 0x60000011f, 0x180000047c});
+constexpr StatTable37 SQR2_TABLE_37({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x1000000000, 0x298, 0x2980, 0x29800, 0x298000, 0x2980000, 0x29800000, 0x298000000, 0x980000053, 0x180000047c, 0x4414, 0x44140, 0x441400, 0x4414000, 0x44140000, 0x441400000, 0x4140000a6, 0x140000ac6, 0x140000ac60, 0xac43e, 0xac43e0, 0xac43e00, 0xac43e000, 0xac43e0000, 0xc43e0011f, 0x43e00101a, 0x3e0010106, 0x1e00101033});
+constexpr StatTable37 SQR4_TABLE_37({0x1, 0x10000, 0x100000000, 0x29800, 0x298000000, 0x44140, 0x441400000, 0xac43e, 0xac43e0000, 0x1e00101033, 0x1010011000, 0x11029a980, 0x9a982b1d3, 0x2b1c45014, 0x4501005f2, 0x1005f8ef80, 0x18efa98941, 0x9897de117, 0x1de10002ad, 0x2990398, 0x190398047c, 0x180443dee4, 0x3ded94ac6, 0x194ac071fa, 0x71c56e1a, 0x56e1adff2, 0x1adffa1690, 0x1a16a9ab31, 0x9ab0957cf, 0x957d85468, 0x18547edba2, 0x1edb9fc515, 0x1fc526c1a4, 0x6c1956aab, 0x156aa5b9d4, 0x5b9f59def, 0x159de6d961});
+constexpr StatTable37 SQR8_TABLE_37({0x1, 0x18efa98941, 0x1fc526c1a4, 0x11352e16c4, 0xba7aa5340, 0x17346e075f, 0xe91c746aa, 0xe560ac1bd, 0xa4544c5d9, 0x11bd3c631f, 0xd70c4b63c, 0xfe77d107c, 0x10548e5288, 0x1183954fb3, 0x19b3aa4bb, 0x782a2943c, 0x1c19ba61de, 0x6ad01fe38, 0xa22701577, 0xb96546ca0, 0x1d7c6c8b9c, 0xffef807e2, 0x16fcc14dc2, 0x110cc4e83c, 0xc3a35629a, 0x1062330476, 0xb2e5d1de1, 0x1ca4e3d229, 0x67826b51b, 0xe7e4c36e7, 0x59f1ac963, 0x12777f22c6, 0x13963d623a, 0x9e305ac92, 0x219b91d13, 0x175bebeb0d, 0xc6b7b5572});
+constexpr StatTable37 SQR16_TABLE_37({0x1, 0xcb88f2f8b, 0x1a2a0be7af, 0xb93048ada, 0x113ed92190, 0xc95a18e2b, 0x1e1cd4a85b, 0x19584a1a66, 0x1b947c28c2, 0x1b52b48e27, 0xe64e7b169, 0x14a256d011, 0xda657196d, 0x1947c1dcb4, 0x18b2fa3851, 0xae3d4171a, 0x658f1f4b9, 0x91852c314, 0x69346cf8e, 0x8224bf36c, 0x1086c810ed, 0x10419bc782, 0x57d6a4e36, 0xfbb31a43e, 0x18b502de05, 0x786795174, 0x1de0f1b7f3, 0x1d456b87dc, 0x1aabb2f3bc, 0xc5b80ef0c, 0x1ce4fd7543, 0x7ca740ca1, 0x29eaec26a, 0x1eb0b42043, 0xca3b2b17, 0x3453101c1, 0x1714c59187});
+constexpr StatTable37 QRT_TABLE_37({0xa3c62e7ba, 0xdc7a0c16a, 0xdc7a0c168, 0x12f7484546, 0xdc7a0c16c, 0xa9803a20, 0x12f748454e, 0xda07064a4, 0xdc7a0c17c, 0x123908de8e, 0xa9803a00, 0x122a888a8e, 0x12f748450e, 0x6790add8, 0xda0706424, 0x12e0a0384c, 0xdc7a0c07c, 0xcb28a2c2, 0x123908dc8e, 0xd09f85e86, 0xa9803e00, 0x124d682b6e, 0x122a88828e, 0x1738711a, 0x12f748550e, 0x73035b8, 0x67908dd8, 0xa0702438, 0xda0702424, 0xe0a0b860, 0x12e0a0b84c, 0x1c7a1c060, 0xdc7a1c07c, 0, 0xcb2aa2c2, 0x100000002c, 0x12390cdc8e});
+typedef Field<uint64_t, 37, 83, StatTable37, &SQR_TABLE_37, &SQR2_TABLE_37, &SQR4_TABLE_37, &SQR8_TABLE_37, &SQR16_TABLE_37, &QRT_TABLE_37, IdTrans, &ID_TRANS, &ID_TRANS> Field37;
+#endif
+
+#ifdef ENABLE_FIELD_INT_38
+// 38 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 5, 5, 5, 5> StatTable38;
+constexpr StatTable38 SQR_TABLE_38({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x1000000000, 0x63, 0x18c, 0x630, 0x18c0, 0x6300, 0x18c00, 0x63000, 0x18c000, 0x630000, 0x18c0000, 0x6300000, 0x18c00000, 0x63000000, 0x18c000000, 0x630000000, 0x18c0000000, 0x2300000063, 0xc0000014a, 0x3000000528});
+constexpr StatTable38 SQR2_TABLE_38({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x1000000000, 0x18c, 0x18c0, 0x18c00, 0x18c000, 0x18c0000, 0x18c00000, 0x18c000000, 0x18c0000000, 0xc0000014a, 0x1405, 0x14050, 0x140500, 0x1405000, 0x14050000, 0x140500000, 0x1405000000, 0x500001ef, 0x500001ef0, 0x100001ef63, 0x1ef7bc, 0x1ef7bc0, 0x1ef7bc00, 0x1ef7bc000, 0x1ef7bc0000, 0x2f7bc00129, 0x37bc00112d, 0x3bc0011027, 0x3c00110022});
+constexpr StatTable38 SQR4_TABLE_38({0x1, 0x10000, 0x100000000, 0x18c00, 0x18c000000, 0x14050, 0x140500000, 0x100001ef63, 0x1ef7bc000, 0x3bc0011027, 0x110001100, 0x110194c0, 0x194c0194c, 0x194d5455, 0xd5455154f, 0x151544a193, 0x4a18c631f, 0xc6319c6ca, 0x19c6c00014, 0x18c8d, 0x18c8d0000, 0xd00014096, 0x1409ddc00, 0x1ddc01efc6, 0x1efd5ab90, 0x15ab9110e1, 0x1110fe85b2, 0x3e85ab5465, 0x2b5445c97a, 0x5c9450993, 0x50994148f, 0x141488b12a, 0x8b134ee36, 0x34ee3a8ecc, 0x3a8ee3edc8, 0x23edeef7ed, 0x2ef7de8bf9, 0x1e8bc14041});
+constexpr StatTable38 SQR8_TABLE_38({0x1, 0x4a18c631f, 0x8b134ee36, 0x10b5c9474c, 0x3330e98ecb, 0x939897650, 0xd74b026b9, 0x860251dd9, 0x3afbe829b4, 0x3ae6afc308, 0x239ecafe00, 0x2acbc94749, 0x3a5770e19e, 0x4052e180b, 0x321fa15712, 0x3a8a4869ef, 0x1948598082, 0x3b1bd98542, 0xc1deb9112, 0x1b5c9242e, 0x338ba58e8b, 0x8abe06d20, 0x145bb1d2a9, 0x1d6e10fbf0, 0x197d522629, 0x2ff1bbe50d, 0xcc1594a16, 0xc94db1b03, 0x3b20e51c56, 0x101d1e5d07, 0x19472478f7, 0x269635a968, 0x2fd4a35802, 0x1b63e116b6, 0x19fdf9d22a, 0x2ef0e4d419, 0x3e80f730f4, 0x29869b04b9});
+constexpr StatTable38 SQR16_TABLE_38({0x1, 0x3f5fe2afaa, 0x4216541b5, 0x33b362f56a, 0x9d630d7e1, 0x11127694c1, 0x3f8daab2d6, 0x153ca20edc, 0x22a747a3de, 0xc6ab16040, 0x19cc9a7e37, 0x449d96001, 0x45a7e7c46, 0x36d11561ce, 0x114b93f52a, 0x42a87f1b3, 0x23112a30bc, 0x400df9212, 0x3aca9544df, 0x140c4b0bcf, 0x2ae2efa6d3, 0x2f7051159c, 0x19cca2f62e, 0x102023d8c0, 0xccc793f0b, 0x2ff4789b55, 0x339e4cd9ba, 0x2b02ab5052, 0x8c1b5db82, 0x2e461e4e32, 0xd93541605, 0x1acf12087, 0x33b88dca2b, 0x1e91723c8b, 0xd81047b2b, 0x2e5e54b97c, 0x85bb507d8, 0x2145b1864b});
+constexpr StatTable38 QRT_TABLE_38({0x34b0ac6430, 0x2223262fa, 0x2223262f8, 0x35554405fe, 0x2223262fc, 0x355514098a, 0x35554405f6, 0x400840, 0x2223262ec, 0x1777726532, 0x35551409aa, 0x15c06fc0, 0x35554405b6, 0x1f5303fec, 0x4008c0, 0x236a21030, 0x2223263ec, 0x1a9008c00, 0x1777726732, 0x3692c60ab6, 0x3555140daa, 0x15556007ee, 0x15c067c0, 0x14a0b030f2, 0x35554415b6, 0x227c06d168, 0x1f5301fec, 0x16c3928fc2, 0x4048c0, 0x3a942c4c0, 0x236a29030, 0x1636a2902e, 0x2223363ec, 0x3a6e898276, 0x1a9028c00, 0x6de74eb2c, 0x1777766732, 0});
+typedef Field<uint64_t, 38, 99, StatTable38, &SQR_TABLE_38, &SQR2_TABLE_38, &SQR4_TABLE_38, &SQR8_TABLE_38, &SQR16_TABLE_38, &QRT_TABLE_38, IdTrans, &ID_TRANS, &ID_TRANS> Field38;
+#endif
+
+#ifdef ENABLE_FIELD_INT_39
+// 39 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 5, 5, 5> StatTable39;
+constexpr StatTable39 SQR_TABLE_39({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x1000000000, 0x4000000000, 0x22, 0x88, 0x220, 0x880, 0x2200, 0x8800, 0x22000, 0x88000, 0x220000, 0x880000, 0x2200000, 0x8800000, 0x22000000, 0x88000000, 0x220000000, 0x880000000, 0x2200000000, 0x800000011, 0x2000000044});
+constexpr StatTable39 SQR2_TABLE_39({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x1000000000, 0x22, 0x220, 0x2200, 0x22000, 0x220000, 0x2200000, 0x22000000, 0x220000000, 0x2200000000, 0x2000000044, 0x404, 0x4040, 0x40400, 0x404000, 0x4040000, 0x40400000, 0x404000000, 0x4040000000, 0x400000088, 0x4000000880, 0x8888, 0x88880, 0x888800, 0x8888000, 0x88880000, 0x888800000, 0x888000011, 0x880000101, 0x800001001});
+constexpr StatTable39 SQR4_TABLE_39({0x1, 0x10000, 0x100000000, 0x2200, 0x22000000, 0x404, 0x4040000, 0x400000088, 0x888800, 0x888000011, 0x100010, 0x1000100000, 0x1000022000, 0x220022000, 0x220004040, 0x40404040, 0x4040400880, 0x4008888880, 0x888888101, 0x881000001, 0x122, 0x1220000, 0x2200000022, 0x260400, 0x2604000000, 0x48c88, 0x48c880000, 0x800009889, 0x98881000, 0x810001221, 0x12201220, 0x2012200264, 0x2002604264, 0x6042604044, 0x604048c8c4, 0x48c8c8c880, 0x48c8898881, 0x988888881, 0x888802201});
+constexpr StatTable39 SQR8_TABLE_39({0x1, 0x4040400880, 0x2002604264, 0xaa8022011, 0x810049ea9, 0x100100010, 0xc04008101, 0x644048ea4c, 0x18c1764441, 0x60f8e8526c, 0x22000122, 0x48c88989a3, 0xae0032001, 0x2a7aeafae5, 0x6a76641225, 0x2036245242, 0x3e9ab0308b, 0x1c49f6fe41, 0x681b069e2d, 0x4edee8cae5, 0x898c04, 0x660daa8880, 0x69cae9ccc1, 0x4881320991, 0xd06280001, 0x1cc8c8e3d9, 0x445fc65628, 0x4c889a8a49, 0x300b8caeec, 0x50d842fc94, 0x1811acb89d, 0x9d22101c, 0x2025aa407e, 0x20370a744a, 0x3cf77cb80b, 0x54a13e66e7, 0x34c17e2e04, 0x5c19fe54c1, 0x6a72cc767d});
+constexpr StatTable39 SQR16_TABLE_39({0x1, 0x37214861ce, 0x689e897065, 0x5678d6ee60, 0x619da834c4, 0x28352752d3, 0x14fed69ec6, 0x5b3d4aa637, 0x682fb8da4d, 0x2ce48c5615, 0x1591ac539c, 0x72d4fbcd0, 0x346b547296, 0x1e7065d419, 0x4e6eb48571, 0x26615d4c2c, 0x60d1c6122e, 0x78d0e2a2eb, 0x52bb3e2980, 0x3c2592d0ab, 0x701ba76b58, 0x5fdf53b685, 0x57cfd2d120, 0x75559e4344, 0x3837a46907, 0x15f961a4ce, 0x397b9a03e9, 0x5a8dd4ab69, 0x3a6ab3356f, 0x215d39c25e, 0x5bbaf82443, 0x6759e3c88c, 0x3c0b862ca1, 0x37eec7e79e, 0x6ce865e38, 0x4a56a338c0, 0x5684636aee, 0x325a019126, 0x24f18a4ef6});
+constexpr StatTable39 QRT_TABLE_39({0x66b02a408c, 0x100420, 0x100422, 0x14206080, 0x100426, 0x5dccefab1c, 0x14206088, 0x9fc11e5b6, 0x100436, 0x5466bea62a, 0x5dccefab3c, 0x9aa110536, 0x142060c8, 0x54739ed6e2, 0x9fc11e536, 0xe7a82c080, 0x100536, 0x4002000, 0x5466bea42a, 0x6a4022000, 0x5dccefaf3c, 0x9e8118536, 0x9aa110d36, 0x5680e080, 0x142070c8, 0x7d293c5b6, 0x54739ef6e2, 0x8d680e080, 0x9fc11a536, 0x6d282c080, 0xe7a824080, 0x800000000, 0x110536, 0x2d680e080, 0x4022000, 0, 0x5466baa42a, 0x46b03a44aa, 0x6a40a2000});
+typedef Field<uint64_t, 39, 17, StatTable39, &SQR_TABLE_39, &SQR2_TABLE_39, &SQR4_TABLE_39, &SQR8_TABLE_39, &SQR16_TABLE_39, &QRT_TABLE_39, IdTrans, &ID_TRANS, &ID_TRANS> Field39;
+typedef FieldTri<uint64_t, 39, 4, RecLinTrans<uint64_t, 6, 6, 6, 6, 5, 5, 5>, &SQR_TABLE_39, &SQR2_TABLE_39, &SQR4_TABLE_39, &SQR8_TABLE_39, &SQR16_TABLE_39, &QRT_TABLE_39, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri39;
+#endif
+
+#ifdef ENABLE_FIELD_INT_40
+// 40 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 5, 5> StatTable40;
+constexpr StatTable40 SQR_TABLE_40({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x1000000000, 0x4000000000, 0x39, 0xe4, 0x390, 0xe40, 0x3900, 0xe400, 0x39000, 0xe4000, 0x390000, 0xe40000, 0x3900000, 0xe400000, 0x39000000, 0xe4000000, 0x390000000, 0xe40000000, 0x3900000000, 0xe400000000, 0x900000004b, 0x400000015e});
+constexpr StatTable40 SQR2_TABLE_40({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x1000000000, 0x39, 0x390, 0x3900, 0x39000, 0x390000, 0x3900000, 0x39000000, 0x390000000, 0x3900000000, 0x900000004b, 0x541, 0x5410, 0x54100, 0x541000, 0x5410000, 0x54100000, 0x541000000, 0x5410000000, 0x41000000dd, 0x1000000d34, 0xd379, 0xd3790, 0xd37900, 0xd379000, 0xd3790000, 0xd37900000, 0xd379000000, 0x3790000115, 0x790000111b, 0x900001111f});
+constexpr StatTable40 SQR4_TABLE_40({0x1, 0x10000, 0x100000000, 0x3900, 0x39000000, 0x541, 0x5410000, 0x41000000dd, 0xd37900, 0xd379000000, 0x111001, 0x1110010000, 0x10003aa90, 0x3aa903900, 0x903900511a, 0x51051541, 0x515410de9, 0x410de9de4d, 0xe9de437815, 0x437801010e, 0x101000038, 0x383939, 0x3839390000, 0x3900057d41, 0x57d444100, 0x444100d6e5, 0xd6ebaa79, 0xebaa7911c6, 0x7911d2791a, 0xd2791102a9, 0x1102b82901, 0xb82902a972, 0x2a96bfed1, 0x6bfed16851, 0xd16859f42e, 0x59f43f61a8, 0x3f61a43794, 0xa43791de59, 0x91de42401f, 0x424000390e});
+constexpr StatTable40 SQR8_TABLE_40({0x1, 0x515410de9, 0x2a96bfed1, 0x13ba41ea90, 0x45bffe2b75, 0x5836900, 0x3887d7e690, 0xd34b688712, 0xc7a3d51557, 0xd1151ada71, 0x51442a740, 0x41cc5cbdb6, 0xc61a5701e9, 0x8757946d91, 0xa99e8b9e65, 0x80a0aca777, 0xc242b5c0e9, 0x6826eccb25, 0xad687ebd2d, 0xad5c69d802, 0x7ed2f8390, 0x51fa78eedf, 0xc0718c96f6, 0xaf4672a8c2, 0xc67436f2fd, 0x56ddb12767, 0x535afb0326, 0xbce1edda33, 0xef36202f0f, 0x45d13015ec, 0x104ab11aef, 0xef96c86d49, 0xc1b790bfc9, 0x2fa610e77f, 0x2a10a27d6e, 0xca5bb10773, 0xfdaf2b4642, 0xb3b4b7e20d, 0xe8bbe4d22e, 0xf9986bd2df});
+constexpr StatTable40 SQR16_TABLE_40({0x1, 0xe88450a7de, 0x3a0a56c3e8, 0x1684757d36, 0xc7f40bf3e9, 0x38aa7009c0, 0x2b6f129659, 0xd1e0fc42e5, 0x96150bc554, 0x9774ef4cc1, 0xd34eebf74d, 0x2d183441ec, 0xeedf6d1c78, 0x3f93c5d217, 0xb924305809, 0xc383bb7c14, 0x3f242bb94e, 0x9313556f6b, 0x2f5e1ecc6b, 0x2e7f9df195, 0xac8b882870, 0xd14f457f55, 0xf9f936148d, 0x719190770, 0x6838b41a21, 0xb95ff30106, 0xc1527dd1c5, 0xe858b5f9b6, 0x9368a791c2, 0x7de23878af, 0x95c610d398, 0xed0edcb032, 0x9548a680b0, 0xc133469e7b, 0x68c96ccbb2, 0x7773231ebb, 0xbd5ef4207c, 0xdf8bd59374, 0xb862414268, 0xfa62b39e42});
+constexpr StatTable40 QRT_TABLE_40({0x624b3cecc, 0xbc5c3f4c6, 0xbc5c3f4c4, 0xde1603e2c, 0xbc5c3f4c0, 0xaabec06cea, 0xde1603e24, 0x6cd9f724c2, 0xbc5c3f4d0, 0xcde1743818, 0xaabec06cca, 0xa138c314ca, 0xde1603e64, 0xaafc00f01a, 0x6cd9f72442, 0xcdca11bb4, 0xbc5c3f5d0, 0xa00002001a, 0xcde1743a18, 0xdf1407b90, 0xaabec068ca, 0xc043b482c8, 0xa138c31cca, 0xcb86977e3c, 0xde1602e64, 0x604596a326, 0xaafc00d01a, 0xcc1c165d0, 0x6cd9f76442, 0x673c94da26, 0xcdca19bb4, 0x67c0940a26, 0xbc5c2f5d0, 0xa4dca19bae, 0xa00000001a, 0x1bc5c2f5d0, 0xcde1703a18, 0, 0xdf1487b90, 0x8df1487b8a});
+typedef Field<uint64_t, 40, 57, StatTable40, &SQR_TABLE_40, &SQR2_TABLE_40, &SQR4_TABLE_40, &SQR8_TABLE_40, &SQR16_TABLE_40, &QRT_TABLE_40, IdTrans, &ID_TRANS, &ID_TRANS> Field40;
+#endif
+}
+
+Sketch* ConstructClMul5Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_33
+ case 33: return new SketchImpl<Field33>(implementation, 33);
+#endif
+#ifdef ENABLE_FIELD_INT_34
+ case 34: return new SketchImpl<Field34>(implementation, 34);
+#endif
+#ifdef ENABLE_FIELD_INT_35
+ case 35: return new SketchImpl<Field35>(implementation, 35);
+#endif
+#ifdef ENABLE_FIELD_INT_36
+ case 36: return new SketchImpl<Field36>(implementation, 36);
+#endif
+#ifdef ENABLE_FIELD_INT_37
+ case 37: return new SketchImpl<Field37>(implementation, 37);
+#endif
+#ifdef ENABLE_FIELD_INT_38
+ case 38: return new SketchImpl<Field38>(implementation, 38);
+#endif
+#ifdef ENABLE_FIELD_INT_39
+ case 39: return new SketchImpl<Field39>(implementation, 39);
+#endif
+#ifdef ENABLE_FIELD_INT_40
+ case 40: return new SketchImpl<Field40>(implementation, 40);
+#endif
+ }
+ return nullptr;
+}
+
+Sketch* ConstructClMulTri5Bytes(int bits, int implementation) {
+ switch (bits) {
+#ifdef ENABLE_FIELD_INT_33
+ case 33: return new SketchImpl<FieldTri33>(implementation, 33);
+#endif
+#ifdef ENABLE_FIELD_INT_34
+ case 34: return new SketchImpl<FieldTri34>(implementation, 34);
+#endif
+#ifdef ENABLE_FIELD_INT_35
+ case 35: return new SketchImpl<FieldTri35>(implementation, 35);
+#endif
+#ifdef ENABLE_FIELD_INT_36
+ case 36: return new SketchImpl<FieldTri36>(implementation, 36);
+#endif
+#ifdef ENABLE_FIELD_INT_39
+ case 39: return new SketchImpl<FieldTri39>(implementation, 39);
+#endif
+ }
+ return nullptr;
+}
diff --git a/src/fields/clmul_6bytes.cpp b/src/fields/clmul_6bytes.cpp
new file mode 100644
index 00000000..d0e71240
--- /dev/null
+++ b/src/fields/clmul_6bytes.cpp
@@ -0,0 +1,170 @@
+/**********************************************************************
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
+ * Distributed under the MIT software license, see the accompanying *
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* This file was substantially auto-generated by doc/gen_params.sage. */
+#include "../fielddefines.h"
+
+#if defined(ENABLE_FIELD_BYTES_INT_6)
+
+#include "clmul_common_impl.h"
+
+#include "../int_utils.h"
+#include "../lintrans.h"
+#include "../sketch_impl.h"
+
+#endif
+
+#include "../sketch.h"
+
+namespace {
+#ifdef ENABLE_FIELD_INT_41
+// 41 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 6, 5> StatTable41;
+constexpr StatTable41 SQR_TABLE_41({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x1000000000, 0x4000000000, 0x10000000000, 0x12, 0x48, 0x120, 0x480, 0x1200, 0x4800, 0x12000, 0x48000, 0x120000, 0x480000, 0x1200000, 0x4800000, 0x12000000, 0x48000000, 0x120000000, 0x480000000, 0x1200000000, 0x4800000000, 0x12000000000, 0x8000000012});
+constexpr StatTable41 SQR2_TABLE_41({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x1000000000, 0x10000000000, 0x48, 0x480, 0x4800, 0x48000, 0x480000, 0x4800000, 0x48000000, 0x480000000, 0x4800000000, 0x8000000012, 0x104, 0x1040, 0x10400, 0x104000, 0x1040000, 0x10400000, 0x104000000, 0x1040000000, 0x10400000000, 0x4000000048, 0x492, 0x4920, 0x49200, 0x492000, 0x4920000, 0x49200000, 0x492000000, 0x4920000000, 0x9200000012, 0x12000000104});
+constexpr StatTable41 SQR4_TABLE_41({0x1, 0x10000, 0x100000000, 0x480, 0x4800000, 0x8000000012, 0x104000, 0x1040000000, 0x4920, 0x49200000, 0x12000000104, 0x1001000, 0x10010000000, 0x48048, 0x480480000, 0x4800001040, 0x10410400, 0x4104000048, 0x492492, 0x4924920000, 0x9200010002, 0x100000100, 0x1000480, 0x10004800000, 0x8000048012, 0x480104000, 0x1040001040, 0x10404920, 0x4049200048, 0x12000492104, 0x4921001000, 0x10010010010, 0x100148048, 0x1480480480, 0x4804805840, 0x8058410412, 0x410410414c, 0x10414d2492, 0x14d24924920, 0x9249259202, 0x12592000004});
+constexpr StatTable41 SQR8_TABLE_41({0x1, 0x10410400, 0x100148048, 0x13040000104, 0x11044801040, 0x924da49202, 0x9680490002, 0x82510514c, 0x8481485932, 0xc83144d832, 0x134d34d6db6, 0x18010048012, 0x165db20004c, 0x4800597052, 0x10131135cd0, 0xcd6cc30d32, 0x160586101cc, 0x15c64969da8, 0x179715681cc, 0x12f3c0ffc74, 0xc7dd3dd3ce, 0x10014c968, 0x1b040048116, 0x35d6801044, 0xda4deda6d0, 0x1de94c85852, 0x1083500114c, 0xc4c9685dfa, 0x18515c6d592, 0x17de69aed7e, 0x16c6c8a6c6c, 0x165cfe1044c, 0xdb004cf018, 0x7075031c98, 0x1d9a90b0d72, 0x1bb2485caee, 0x1cbe4dfd48a, 0x1f1540b7400, 0xc62bc7fd02, 0x147b5103f2e, 0x390ee8bcc6});
+constexpr StatTable41 SQR16_TABLE_41({0x1, 0x61deee38fe, 0xe00adae2e, 0x1ea53eaa95a, 0x503e540566, 0xabc8e7f89a, 0x1bf760d86ac, 0x94cce9c722, 0x15c8006ee5c, 0x7aba20c1da, 0x12662a9603e, 0x5fe76acec4, 0x1e6beca9e42, 0x1efc8f7a000, 0x165997c6d7e, 0xee947a07ee, 0xd9bd741142, 0xaa304566c0, 0x5fe336e356, 0x11f1021b80c, 0xd34e5a1674, 0x99ed56b9dc, 0x9afae0eca, 0x1a5830b390e, 0x1be1a63eb7e, 0x141e77e141c, 0xee3be92168, 0xa93823d65c, 0x18a59f4b19c, 0xce69942af6, 0x3f7b319c0e, 0xba83a4a7b4, 0x7da4b6fcde, 0x17f79268f10, 0x1222602d048, 0x1b4b2f326b8, 0x159abff0786, 0xb35534a7a2, 0x84bbc48050, 0x173d5cbf330, 0x2897dd6f58});
+constexpr StatTable41 QRT_TABLE_41({0, 0x1599a5e0b0, 0x1599a5e0b2, 0x105c119e0, 0x1599a5e0b6, 0x1a2030452a6, 0x105c119e8, 0x1a307c55b2e, 0x1599a5e0a6, 0x1ee3f47bc8e, 0x1a203045286, 0x400808, 0x105c119a8, 0x1a3038573a6, 0x1a307c55bae, 0x4d2882a520, 0x1599a5e1a6, 0x1ffbaa0b720, 0x1ee3f47be8e, 0x4d68c22528, 0x1a203045686, 0x200006, 0x400008, 0x1b79a21b200, 0x105c109a8, 0x1ef3886a526, 0x1a3038553a6, 0x1b692209200, 0x1a307c51bae, 0x5d99a4e1a6, 0x4d28822520, 0x185e109ae, 0x1599a4e1a6, 0x4e3f43be88, 0x1ffbaa2b720, 0x4000000000, 0x1ee3f43be8e, 0x18000000006, 0x4d68ca2528, 0xa203145680, 0x1a203145686});
+typedef Field<uint64_t, 41, 9, StatTable41, &SQR_TABLE_41, &SQR2_TABLE_41, &SQR4_TABLE_41, &SQR8_TABLE_41, &SQR16_TABLE_41, &QRT_TABLE_41, IdTrans, &ID_TRANS, &ID_TRANS> Field41;
+typedef FieldTri<uint64_t, 41, 3, RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 6, 5>, &SQR_TABLE_41, &SQR2_TABLE_41, &SQR4_TABLE_41, &SQR8_TABLE_41, &SQR16_TABLE_41, &QRT_TABLE_41, IdTrans, &ID_TRANS, &ID_TRANS> FieldTri41;
+#endif
+
+#ifdef ENABLE_FIELD_INT_42
+// 42 bit field
+typedef RecLinTrans<uint64_t, 6, 6, 6, 6, 6, 6, 6> StatTable42;
+constexpr StatTable42 SQR_TABLE_42({0x1, 0x4, 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000, 0x1000000, 0x4000000, 0x10000000, 0x40000000, 0x100000000, 0x400000000, 0x1000000000, 0x4000000000, 0x10000000000, 0x81, 0x204, 0x810, 0x2040, 0x8100, 0x20400, 0x81000, 0x204000, 0x810000, 0x2040000, 0x8100000, 0x20400000, 0x81000000, 0x204000000, 0x810000000, 0x2040000000, 0x8100000000, 0x20400000000, 0x1000000102, 0x4000000408, 0x10000001020});
+constexpr StatTable42 SQR2_TABLE_42({0x1, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000, 0x100000000, 0x1000000000, 0x10000000000, 0x204, 0x2040, 0x20400, 0x204000, 0x2040000, 0x20400000, 0x204000000, 0x2040000000, 0x20400000000, 0x4000000408, 0x4001, 0x40010, 0x400100, 0x4001000, 0x40010000, 0x400100000, 0x4001000000, 0x10000081, 0x100000810, 0x1000008100, 0x10000081000, 0x810204, 0x8102040, 0x81020400, 0x810204000, 0x8102040000, 0x1020400102, 0x10204001020, 0x2040010004, 0x20400100040, 0x4001000008});
+constexpr StatTable42 SWhy this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.