packages feed

hwsl2 0.3.0.1 → 0.3.1.0

raw patch · 12 files changed

+561/−374 lines, 12 filesdep ~Cabal

Dependency ranges changed: Cabal

Files

README.md view
@@ -16,3 +16,5 @@     mconcat (parMap rpar hash cs) == hash m  All operations in this package are implemented in a very efficient manner using SSE instructions.++![diagram](https://raw.githubusercontent.com/srijs/hwsl2-core/master/cat.png)
dist/build/testStub/testStub-tmp/testStub.hs view
@@ -1,5 +1,5 @@ module Main ( main ) where-import Distribution.Simple.Test.LibV09 ( stubMain )+import Distribution.Simple.Test ( stubMain ) import Data.Hash.SL2.Test ( tests ) main :: IO () main = stubMain tests
hwsl2.cabal view
@@ -4,13 +4,13 @@ -- The name of the package. name:                hwsl2 --- The package version.  See the Haskell package versioning policy (PVP) +-- The package version.  See the Haskell package versioning policy (PVP) -- for standards guiding when and how versions should be incremented. -- http://www.haskell.org/haskellwiki/Package_versioning_policy -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             0.3.0.1+version:             0.3.1.0  -- A short (one-line) description of the package. synopsis:            Hashing with SL2@@ -47,53 +47,59 @@ -- The package author(s). author:              Sam Rijs --- An email address to which users can send suggestions, bug reports, and +-- An email address to which users can send suggestions, bug reports, and -- patches. maintainer:          srijs@airpost.net  -- A copyright notice.--- copyright:           +-- copyright:  category:            Data  build-type:          Simple --- Extra files to be distributed with the package, such as examples or a +-- Extra files to be distributed with the package, such as examples or a -- README. extra-source-files:  README.md+                     src/core/sl2-inl.h src/core/gf2p127-inl.h  -- Constraint on the version of Cabal needed to build this package. cabal-version:       >=1.10 +flag avx2+  description:        Enable AVX 2 optimisations.+  default:            True  library   -- Modules exported by the library.   exposed-modules:     Data.Hash.SL2                        Data.Hash.SL2.Mutable                        Data.Hash.SL2.Unsafe-  +   -- Modules included in this library but not exported.   other-modules:       Data.Hash.SL2.Internal-  +   -- LANGUAGE extensions used by modules in this package.   other-extensions:    ForeignFunctionInterface CApiFFI                        Safe Trustworthy Unsafe-  +   -- Other library packages from which modules are imported.   build-depends:       base >=4.7 && <4.8, bytestring >=0.10 && <0.11-  +   -- Directories containing source files.   hs-source-dirs:      src    ghc-options:         -fwarn-unused-imports    -- Options for foreign source files.-  include-dirs:        src-  includes:            src/sl2-inl.h src/gf2p127-inl.h-  install-includes:    src/sl2-inl.h src/gf2p127-inl.h-  cc-options:          -msse2 -msse4.1 -mpclmul-  ghc-options:         -optc-msse2 -optc-msse4.1 -optc-mpclmul-  +  include-dirs:        src/core+  if flag(avx2)+    cc-options:        -Wall -O3 -mavx2 -msse4.1 -msse2 -mpclmul+    ghc-options:       -O3 -optc-mavx2 -optc-msse4.1 -msse2 -optc-mpclmul+  else+    cc-options:        -Wall -O3 -msse4.1 -msse2 -mpclmul+    ghc-options:       -O3 -optc-msse4.1 -msse2 -optc-mpclmul+   -- Base language which the package is written in.   default-language:    Haskell2010 @@ -107,15 +113,18 @@                        Data.Hash.SL2.Unsafe                        Data.Hash.SL2.Internal   build-depends:       base >=4.7 && <4.8,-                       Cabal >=1.22.0.0,+                       Cabal >=1.9.2,                        bytestring >=0.10 && <0.11,                        QuickCheck >=2.7 && <2.8,                        quickcheck-properties>=0.1 && <0.2,                        cabal-test-quickcheck>=0.1 && <0.2-  include-dirs:        src-  includes:            src/sl2-inl.h src/gf2p127-inl.h-  install-includes:    src/sl2-inl.h src/gf2p127-inl.h-  ghc-options:         -optc-msse2 -optc-msse4.1 -optc-mpclmul+  include-dirs:        src/core+  if flag(avx2)+    cc-options:        -Wall -O3 -mavx2 -msse4.1 -msse2 -mpclmul+    ghc-options:       -O3 -optc-mavx2 -optc-msse4.1 -msse2 -optc-mpclmul+  else+    cc-options:        -Wall -O3 -msse4.1 -msse2 -mpclmul+    ghc-options:       -O3 -optc-msse4.1 -msse2 -optc-mpclmul  benchmark bench   type:                exitcode-stdio-1.0@@ -126,12 +135,15 @@                        Data.Hash.SL2.Unsafe                        Data.Hash.SL2.Internal   build-depends:       base >=4.7 && <4.8,-                       Cabal >=1.22.0.0,+                       Cabal >=1.9.2,                        bytestring >=0.10 && <0.11,                        criterion >=1.0 && <1.1,                        cryptohash >=0.11 && <0.12,                        parallel >=3.2 && <3.3-  include-dirs:        src-  includes:            src/sl2-inl.h src/gf2p127-inl.h-  install-includes:    src/sl2-inl.h src/gf2p127-inl.h-  ghc-options:         -rtsopts -threaded -optc-msse2 -optc-msse4.1 -optc-mpclmul+  include-dirs:        src/core+  if flag(avx2)+    cc-options:        -Wall -O3 -mavx2 -msse4.1 -msse2 -mpclmul+    ghc-options:       -rtsopts -threaded -O3 -optc-mavx2 -optc-msse4.1 -msse2 -optc-mpclmul+  else+    cc-options:        -Wall -O3 -msse4.1 -msse2 -mpclmul+    ghc-options:       -rtsopts -threaded -O3 -optc-msse4.1 -msse2 -optc-mpclmul
src/Data/Hash/SL2.hs view
@@ -43,7 +43,7 @@   , unpack8, unpack16, unpack32, unpack64   ) where -import Prelude hiding (concat)+import Prelude hiding (concat, foldl, foldr)  import Data.Hash.SL2.Internal (Hash) import Data.Hash.SL2.Unsafe@@ -56,7 +56,7 @@ import Data.Word import Data.Monoid import Data.Functor-import Data.Foldable (Foldable)+import Data.Foldable (Foldable, foldl, foldl', foldr, foldr')  instance Show Hash where   show h = unsafePerformIO $ unsafeUseAsPtr h Mutable.serialize@@ -64,6 +64,9 @@ instance Eq Hash where   a == b = unsafePerformIO $ unsafeUseAsPtr2 a b Mutable.eq +instance Ord Hash where+  compare a b = unsafePerformIO $ unsafeUseAsPtr2 a b Mutable.cmp+ instance Monoid Hash where   mempty = unit   mappend = concat@@ -77,21 +80,27 @@ -- A significantly faster equivalent of @((. 'hash') . 'concat')@. append :: Hash -> ByteString -> Hash append h s = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.append s+{-# RULES "hash/concat" forall h s . concat h (hash s) = append h s #-}  -- | /O(n)/ Prepend the hash of the 'ByteString' to the existing 'Hash'. -- A significantly faster equivalent of @('concat' . 'hash')@. prepend :: ByteString -> Hash -> Hash prepend s h = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.prepend s+{-# RULES "concat/hash" forall s h . concat (hash s) h = prepend s h #-}  -- | /O(n)/ Append the hash of every 'ByteString' to the existing 'Hash', from left to right. -- A significantly faster equivalent of @('foldl' 'append')@. foldAppend :: Foldable t => Hash -> t ByteString -> Hash foldAppend h ss = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.foldAppend ss+{-# RULES "foldl/append" forall h ss . foldl append h ss = foldAppend h ss #-}+{-# RULES "foldl'/append" forall h ss . foldl' append h ss = foldAppend h ss #-}  -- | /O(n)/ Prepend the hash of every 'ByteString' to the existing 'Hash', from right to left. -- A significantly faster equivalent of @('flip' ('foldr' 'prepend'))@. foldPrepend :: Foldable t => t ByteString -> Hash -> Hash foldPrepend ss h = fst $ unsafePerformIO $ Mutable.withCopy h $ Mutable.foldPrepend ss+{-# RULES "foldr/prepend" forall ss h . foldr prepend h ss = foldPrepend ss h #-}+{-# RULES "foldr'/prepend" forall ss h . foldr' prepend h ss = foldPrepend ss h #-}  -- | /O(1)/ The unit element for concatenation. Alias for 'mempty'. unit :: Hash@@ -100,6 +109,7 @@ -- | /O(1)/ Concatenate two hashes. Alias for 'mappend'. concat :: Hash -> Hash -> Hash concat a b = fst $ unsafePerformIO $ unsafeWithNew (unsafeUseAsPtr2 a b . Mutable.concat)+{-# INLINE[1] concat #-}  -- | /O(n)/ Concatenate a list of hashes. Alias for 'mconcat'. concatAll :: [Hash] -> Hash
src/Data/Hash/SL2/Benchmark.hs view
@@ -6,6 +6,7 @@  import qualified Data.ByteString as B import qualified Crypto.Hash.SHA256 as SHA256+import qualified Crypto.Hash.SHA512 as SHA512  import Criterion.Main @@ -14,8 +15,9 @@ bs4M = B.pack $ take (4 * 1024 * 1024) $ cycle [0..255]  main = defaultMain-  [ bench "hwsl2 append" $ whnf (append union) bs4M-  , bench "hwsl2 prepend" $ whnf (flip prepend union) bs4M+  [ bench "hwsl2 append" $ whnf (append unit) bs4M+  , bench "hwsl2 prepend" $ whnf (flip prepend unit) bs4M   , bench "hwsl2 append parallel" $ whnf (concatAll . (parMap rpar hash)) [bs1M, bs1M, bs1M, bs1M]   , bench "sha256" $ whnf SHA256.hash bs4M+  , bench "sha512" $ whnf SHA512.hash bs4M   ]
src/Data/Hash/SL2/Internal.hs view
@@ -18,6 +18,9 @@ foreign import capi "sl2-inl.h sl2_eq"   eq :: Ptr Hash -> Ptr Hash -> IO CInt +foreign import capi "sl2-inl.h sl2_cmp"+  cmp :: Ptr Hash -> Ptr Hash -> IO CInt+ foreign import capi "sl2-inl.h sl2_unit"   unit :: Ptr Hash -> IO () 
src/Data/Hash/SL2/Mutable.hs view
@@ -2,7 +2,7 @@  module Data.Hash.SL2.Mutable   ( valid-  , eq+  , eq, cmp   , unit   , concat   , append, prepend@@ -34,6 +34,11 @@ eq :: Ptr Hash -> Ptr Hash -> IO Bool {-# INLINE eq #-} eq a b = fmap toBool $ Internal.eq a b++-- | /O(1)/ Compare two hashes.+cmp :: Ptr Hash -> Ptr Hash -> IO Ordering+{-# INLINE cmp #-}+cmp a b = fmap (compare 0) $ Internal.cmp a b  -- | /O(1)/ Set the 'Hash' to the empty value. unit :: Ptr Hash -> IO ()
src/Data/Hash/SL2/Test.hs view
@@ -29,7 +29,34 @@ tests :: IO [Test] tests = return -  [ testGroup "packing"+  [ testGroup "equality"++    [ testProperty "true" $+        \a -> hash a == hash a++    , testProperty "false" $+        \a b -> (a /= b) ==> hash a /= hash b+    ]++  , testGroup "compare"++    [ testProperty "eq" $+        \a -> compare (hash a) (hash a) == EQ++    , testProperty "gt" $+        \a b c -> (a > b && b > c) ==> (a :: Hash) > c++    , testProperty "ge" $+        \a b c -> (a >= b && b >= c) ==> (a :: Hash) >= c++    , testProperty "lt" $+        \a b c -> (a < b && b < c) ==> (a :: Hash) < c++    , testProperty "le" $+        \a b c -> (a <= b && b <= c) ==> (a :: Hash) <= c+    ]++  , testGroup "packing"      [ testProperty "identity 8-bit" $         \a -> Just a == pack8 (unpack8 a)
+ src/core/gf2p127-inl.h view
@@ -0,0 +1,138 @@+#pragma once++#include <stdio.h>+#include <stdint.h>+#include <immintrin.h>+#include <smmintrin.h>+#include <wmmintrin.h>++typedef __m128i gf2p127_t;+#ifdef __AVX2__+typedef __m256i gf2p127x2_t;+#endif++static const inline+_Bool gf2p127_valid(const gf2p127_t a) {+  return (_mm_extract_epi64(a, 1) & (UINT64_C(1) << 63)) == 0;+}++static const inline+_Bool gf2p127_eq(const gf2p127_t a, const gf2p127_t b) {+  _Bool lo = _mm_extract_epi64(a, 0) == _mm_extract_epi64(b, 0);+  _Bool hi = _mm_extract_epi64(a, 1) == _mm_extract_epi64(b, 1);+  return lo && hi;+}++static const inline+gf2p127_t gf2p127_zero() {+  return _mm_setzero_si128();+}++static const inline+gf2p127_t gf2p127_from_int(int a) {+  return _mm_cvtsi32_si128(a);+}++static const inline+gf2p127_t gf2p127_mul_bit(const gf2p127_t a, const _Bool bit) {+  return _mm_slli_epi64(a, !bit * 64);+}++static const inline+gf2p127_t gf2p127_add(const gf2p127_t a, const gf2p127_t b) {+  return _mm_xor_si128(a, b);+}++static const inline+gf2p127_t gf2p127_mul_00(const gf2p127_t a) {+  return _mm_setzero_si128();+}++static const inline+gf2p127_t gf2p127_mul_01(const gf2p127_t a) {+  return a;+}++static const gf2p127_t *minmax __attribute__((__aligned__(16))) =+  (gf2p127_t *)(uint64_t [4]){0, 0, UINT64_MAX, UINT64_MAX};++static const gf2p127_t *x127 __attribute__((__aligned__(16))) =+  (gf2p127_t *)(uint32_t [4]){0, 0, 0, 1 << 31};++static const inline+gf2p127_t gf2p127_mul_10(const gf2p127_t a) {+  // Shift lower and upper halves left by one bit,+  // resembling a multiplication by two.+  gf2p127_t sl = _mm_slli_epi64(a, 1);+  // Check for a x^127 overflow, and add the polynom and carry bit.+  gf2p127_t one = _mm_srli_epi64(_mm_alignr_epi8(a, sl, 8), 63);+  gf2p127_t over = _mm_and_si128(sl, _mm_load_si128(x127));+  gf2p127_t x127x63 = _mm_unpackhi_epi64(over, over);+  return _mm_xor_si128(_mm_xor_si128(sl, one), x127x63);+}++#ifdef __AVX2__+static const inline+gf2p127x2_t gf2p127x2_mul_10(const gf2p127x2_t ab) {+  // Shift lower and upper halves left by one bit,+  // resembling a multiplication by two.+  gf2p127x2_t sl = _mm256_slli_epi64(ab, 1);+  // Check for the x^63 carry bit, and the x^127 overflow, and construct x^64 + 1 polynomial.+  gf2p127x2_t carry = _mm256_srli_epi64(_mm256_alignr_epi8(ab, sl, 8), 63);+  gf2p127x2_t carried = _mm256_xor_si256(sl, carry);+  // Check for the x^127 overflow, and construct the x^127 + x^63 polymomial.+  gf2p127x2_t over1 = _mm256_srli_epi64(sl, 63);+  gf2p127x2_t over2 = _mm256_slli_epi64(over1, 63);+  gf2p127x2_t overhi = _mm256_unpackhi_epi64(over2, over2);+  return _mm256_xor_si256(overhi, carried);+}+#endif++static const inline+gf2p127_t gf2p127_mul_11(const gf2p127_t a) {+  gf2p127_t mul01 = gf2p127_mul_01(a);+  gf2p127_t mul10 = gf2p127_mul_10(a);+  return _mm_xor_si128(mul01, mul10);+};++static const inline+gf2p127_t gf2p127_mul(const gf2p127_t a, const gf2p127_t b) {+  gf2p127_t tmp, lo, hi;++  // Multiplication (Karatsuba):+  //   tmp <- (a0 + a1) * (b0 + b1)+  tmp = _mm_xor_si128(_mm_unpacklo_epi64(a, b), _mm_unpackhi_epi64(a, b));+  tmp = _mm_clmulepi64_si128(tmp, tmp, 0x10);+  //   lo <- a0 * b0+  lo = _mm_clmulepi64_si128(a, b, 0x00);+  //   hi <- a1 * b1+  hi = _mm_clmulepi64_si128(a, b, 0x11);+  //   tmp <- (a0 + a1) * (b0 + b1) + a0 * b0 + a1 * b1+  tmp = _mm_xor_si128(tmp, _mm_xor_si128(lo, hi));+  //   lo <- a0 * b0 + low64[(a0 + a1) * (b0 + b1) + a0 * b0 + a1 * b1] * x^64+  lo = _mm_xor_si128(lo, _mm_slli_si128(tmp, 8));+  //   hi <- a1 * b1 + high64[(a0 + a1) * (b0 + b1) + a0 * b0 + a1 * b1]+  hi = _mm_xor_si128(hi, _mm_srli_si128(tmp, 8));++  // Reduction (modulo f(x) = x^127 + x^63 + 1)+  //   tmp <- low64[hi] * x^64 + high64[lo]+  tmp = _mm_alignr_epi8(hi, lo, 8);+  tmp = _mm_xor_si128(tmp, hi);+  hi = _mm_slli_epi64(hi, 1);+  lo = _mm_xor_si128(lo, hi);+  hi = _mm_unpackhi_epi64(hi, tmp);+  lo = _mm_xor_si128(lo, hi);+  tmp = _mm_srli_epi64(tmp, 63);+  lo = _mm_xor_si128(lo, tmp);+  hi = _mm_unpacklo_epi64(tmp, tmp);+  lo = _mm_xor_si128(lo, _mm_slli_epi64(hi, 63));++  return lo;+}++static inline+char *gf2p127_hex(char *str, const gf2p127_t m) {+  sprintf(str, "%.16llx%.16llx", _mm_extract_epi64(m, 1),+                                 _mm_extract_epi64(m, 0));+  return str;+}
+ src/core/sl2-inl.h view
@@ -0,0 +1,330 @@+#pragma once++#include "gf2p127-inl.h"++typedef gf2p127_t sl2_t[2][2] __attribute__((__aligned__(16)));++static inline+_Bool sl2_valid(sl2_t a) {+  gf2p127_t det = gf2p127_add(gf2p127_mul(a[0][0], a[1][1]),+                              gf2p127_mul(a[0][1], a[1][0]));+  return _mm_extract_epi64(det, 0) == 1 &&+         _mm_extract_epi64(det, 1) == 0 &&+         gf2p127_valid(a[0][0]) &&+         gf2p127_valid(a[0][1]) &&+         gf2p127_valid(a[1][0]) &&+         gf2p127_valid(a[1][1]);+}++static inline+_Bool sl2_eq(sl2_t a, sl2_t b) {+  return gf2p127_eq(a[0][0], b[0][0]) &&+         gf2p127_eq(a[0][1], b[0][1]) &&+         gf2p127_eq(a[1][0], b[1][0]) &&+         gf2p127_eq(a[1][1], b[1][1]);+}++static inline+int sl2_cmp(sl2_t a, sl2_t b) {+  uint64_t *ua = (uint64_t *)a;+  uint64_t *ub = (uint64_t *)b;+  int i;+  for (i = 0; i < sizeof(sl2_t) / sizeof(uint64_t); i++) {+    if (ua[i] == ub[i]) {+      continue;+    }+    if (ua[i] > ub[i]) {+      return 1;+    }+    if (ua[i] < ub[i]) {+      return -1;+    }+  }+  return 0;+}++static inline+void sl2_copy(sl2_t dst, sl2_t src) {+  dst[0][0] = src[0][0];+  dst[0][1] = src[0][1];+  dst[1][0] = src[1][0];+  dst[1][1] = src[1][1];+}++#ifdef __AVX2__+static inline+void sl2_mul_bit_left_x2(gf2p127x2_t *b00b01, gf2p127x2_t *b10b11, gf2p127_t bits) {+  // A: {00 = 10, 01 = 01, 10 = 01, 11 = 00}+  // B: {00 = 10, 01 = 11, 10 = 01, 11 = 01}+  gf2p127x2_t bb = _mm256_broadcastsi128_si256(bits);+  gf2p127x2_t masked = _mm256_and_si256(*b10b11, bb);+  gf2p127x2_t maskedadd = _mm256_xor_si256(*b00b01, masked);+  gf2p127x2_t mul = gf2p127x2_mul_10(maskedadd);+  gf2p127x2_t muladd = _mm256_xor_si256(*b10b11, mul);+  *b10b11 = maskedadd;+  *b00b01 = muladd;+}+#endif++static inline+void sl2_mul_bit_left(gf2p127_t *b00, gf2p127_t *b01, gf2p127_t *b10, gf2p127_t *b11, gf2p127_t bits) {+  // A: {00 = 10, 01 = 01, 10 = 01, 11 = 00}+  // B: {00 = 10, 01 = 11, 10 = 01, 11 = 01}+  gf2p127_t b10_ = *b10;+  gf2p127_t b11_ = *b11;+  *b10 = gf2p127_add(*b00, _mm_and_si128(*b10, bits));+  *b11 = gf2p127_add(*b01, _mm_and_si128(*b11, bits));+  *b00 = gf2p127_add(b10_, gf2p127_mul_10(*b10));+  *b01 = gf2p127_add(b11_, gf2p127_mul_10(*b11));+}++#ifdef __AVX2__+static inline+void sl2_mul_bits_left_x2(gf2p127x2_t *b00b01, gf2p127x2_t *b10b11, unsigned char byte) {+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 0) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 1) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 2) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 3) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 4) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 5) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 6) & 1]));+  sl2_mul_bit_left_x2(b00b01, b10b11, _mm_load_si128(&minmax[(byte >> 7) & 1]));+}+#endif++static inline+void sl2_mul_bits_left(gf2p127_t *b00, gf2p127_t *b01, gf2p127_t *b10, gf2p127_t *b11, unsigned char byte) {+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 0) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 1) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 2) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 3) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 4) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 5) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 6) & 1]));+  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 7) & 1]));+}++#ifdef __AVX2__+static inline+void sl2_mul_buf_left(sl2_t b, unsigned char *buf, size_t n) {+  gf2p127x2_t b00b01 = _mm256_loadu2_m128i(&b[0][0], &b[0][1]);+  gf2p127x2_t b10b11 = _mm256_loadu2_m128i(&b[1][0], &b[1][1]);+  size_t i;+  for (i = n; i > 0; i--) {+    sl2_mul_bits_left_x2(&b00b01, &b10b11, buf[i - 1]);+  }+  _mm256_storeu2_m128i(&b[0][0], &b[0][1], b00b01);+  _mm256_storeu2_m128i(&b[1][0], &b[1][1], b10b11);+}+#else+static inline+void sl2_mul_buf_left(sl2_t b, unsigned char *buf, size_t n) {+  gf2p127_t b00 = b[0][0];+  gf2p127_t b01 = b[0][1];+  gf2p127_t b10 = b[1][0];+  gf2p127_t b11 = b[1][1];+  size_t i;+  for (i = n; i > 0; i--) {+    sl2_mul_bits_left(&b00, &b01, &b10, &b11, buf[i - 1]);+  }+  b[0][0] = b00;+  b[0][1] = b01;+  b[1][0] = b10;+  b[1][1] = b11;+}+#endif++#ifdef __AVX2__+static inline+void sl2_mul_bit_right_x2(gf2p127x2_t *a00a10, gf2p127x2_t *a01a11, gf2p127_t bits) {+  // A: {00 = 10, 01 = 01, 10 = 01, 11 = 00}+  // B: {00 = 10, 01 = 11, 10 = 01, 11 = 01}+  gf2p127x2_t bb = _mm256_broadcastsi128_si256(bits);+  gf2p127x2_t mul = gf2p127x2_mul_10(*a00a10);+  gf2p127x2_t muladd = _mm256_xor_si256(mul, *a01a11);+  gf2p127x2_t masked = _mm256_and_si256(muladd, bb);+  gf2p127x2_t maskedadd = _mm256_xor_si256(masked, *a00a10);+  *a01a11 = maskedadd;+  *a00a10 = muladd;+}+#endif++static inline+void sl2_mul_bit_right(gf2p127_t *a00, gf2p127_t *a01, gf2p127_t *a10, gf2p127_t *a11, gf2p127_t bits) {+  // A: {00 = 10, 01 = 01, 10 = 01, 11 = 00}+  // B: {00 = 10, 01 = 11, 10 = 01, 11 = 01}+  gf2p127_t a00_ = *a00;+  gf2p127_t a10_ = *a10;+  *a00 = gf2p127_add(gf2p127_mul_10(*a00), *a01);+  *a10 = gf2p127_add(gf2p127_mul_10(*a10), *a11);+  *a01 = gf2p127_add(a00_, _mm_and_si128(*a00, bits));+  *a11 = gf2p127_add(a10_, _mm_and_si128(*a10, bits));+}++#ifdef __AVX2__+static inline+void sl2_mul_bits_right_x2(gf2p127x2_t *a00a01, gf2p127x2_t *a10a11, unsigned char byte) {+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 7) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 6) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 5) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 4) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 3) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 2) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 1) & 1]));+  sl2_mul_bit_right_x2(a00a01, a10a11, _mm_load_si128(&minmax[(byte >> 0) & 1]));+}+#endif++static inline+void sl2_mul_bits_right(gf2p127_t *a00, gf2p127_t *a01, gf2p127_t *a10, gf2p127_t *a11, unsigned char byte) {+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 7) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 6) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 5) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 4) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 3) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 2) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 1) & 1]));+  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 0) & 1]));+}++#ifdef __AVX2__+static inline+void sl2_mul_buf_right(sl2_t a, unsigned char *buf, size_t n) {+  size_t i;+  gf2p127x2_t a00a10 = _mm256_loadu2_m128i(&a[0][0], &a[1][0]);+  gf2p127x2_t a01a11 = _mm256_loadu2_m128i(&a[0][1], &a[1][1]);+  for (i = 0; i < n; i++) {+    sl2_mul_bits_right_x2(&a00a10, &a01a11, buf[i]);+  }+  _mm256_storeu2_m128i(&a[0][1], &a[1][1], a01a11);+  _mm256_storeu2_m128i(&a[0][0], &a[1][0], a00a10);+}+#else+static inline+void sl2_mul_buf_right(sl2_t a, unsigned char *buf, size_t n) {+  gf2p127_t a00 = _mm_load_si128(&a[0][0]);+  gf2p127_t a01 = _mm_load_si128(&a[0][1]);+  gf2p127_t a10 = _mm_load_si128(&a[1][0]);+  gf2p127_t a11 = _mm_load_si128(&a[1][1]);+  size_t i;+  for (i = 0; i < n; i++) {+    sl2_mul_bits_right(&a00, &a01, &a10, &a11, buf[i]);+  }+  a[0][0] = a00;+  a[0][1] = a01;+  a[1][0] = a10;+  a[1][1] = a11;+}+#endif++static inline+void sl2_mul(sl2_t c, sl2_t a, sl2_t b) {+  // Strassen algorithm+  gf2p127_t m0, m1, m2, m3, m4, m5, m6;+  m0 = gf2p127_mul(gf2p127_add(a[0][0], a[1][1]),+                   gf2p127_add(b[0][0], b[1][1]));+  m1 = gf2p127_mul(gf2p127_add(a[1][0], a[1][1]), b[0][0]);+  m2 = gf2p127_mul(a[0][0], gf2p127_add(b[0][1], b[1][1]));+  m3 = gf2p127_mul(a[1][1], gf2p127_add(b[1][0], b[0][0]));+  m4 = gf2p127_mul(gf2p127_add(a[0][0], a[0][1]), b[1][1]);+  m5 = gf2p127_mul(gf2p127_add(a[1][0], a[0][0]),+                   gf2p127_add(b[0][0], b[0][1]));+  m6 = gf2p127_mul(gf2p127_add(a[0][1], a[1][1]),+                   gf2p127_add(b[1][0], b[1][1]));+  c[0][0] = gf2p127_add(gf2p127_add(m0, m3), gf2p127_add(m4, m6));+  c[0][1] = gf2p127_add(m2, m4);+  c[1][0] = gf2p127_add(m1, m3);+  c[1][1] = gf2p127_add(gf2p127_add(m0, m1), gf2p127_add(m2, m5));+}++static inline+void sl2_mul_byte_left(sl2_t b, unsigned char byte, sl2_t m[256]) {+  sl2_mul(m[byte], b, b);+}++static inline+void sl2_mul_byte_right(sl2_t a, unsigned char byte, sl2_t m[256]) {+  sl2_mul(a, m[byte], a);+}++static inline+void sl2_init(sl2_t m[2]) {+  m[0][0][0] = gf2p127_from_int(2);+  m[0][0][1] = gf2p127_from_int(1);+  m[0][1][0] = gf2p127_from_int(1);+  m[0][1][1] = gf2p127_from_int(0);+  m[1][0][0] = gf2p127_from_int(2);+  m[1][0][1] = gf2p127_from_int(3);+  m[1][1][0] = gf2p127_from_int(1);+  m[1][1][1] = gf2p127_from_int(1);+}++static inline+void sl2_unit(sl2_t a) {+  a[0][0] = gf2p127_from_int(1);+  a[0][1] = gf2p127_from_int(0);+  a[1][0] = gf2p127_from_int(0);+  a[1][1] = gf2p127_from_int(1);+}++static inline+char *sl2_hex(char *buf, sl2_t a) {+  gf2p127_hex(&buf[0],  a[0][0]);+  gf2p127_hex(&buf[32], a[0][1]);+  gf2p127_hex(&buf[64], a[1][0]);+  gf2p127_hex(&buf[96], a[1][1]);+  return buf;+}++static const unsigned char b64[64] =+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";++static const unsigned char unb64[256] = {+  ['A'] =  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,+          13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,+  ['a'] = 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,+  ['0'] = 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,+  ['-'] = 62, ['_'] = 63+};++static inline+void sl2_serialize(sl2_t m, unsigned char buf[86]) {++  int i, j;+  unsigned char a, b, c, *data = (unsigned char *)m;++  for (i = j = 0; i <= 64 - 3; i += 3, j += 4) {+    a = data[i + 0];+    b = data[i + 1];+    c = data[i + 2];+    buf[j + 0] = b64[a >> 2];+    buf[j + 1] = b64[((0x03 & a) << 4) + (b >> 4)];+    buf[j + 2] = b64[((0x0f & b) << 2) + (c >> 6)];+    buf[j + 3] = b64[0x3f & c];+  }++  buf[84] = b64[data[i] >> 2];+  buf[85] = b64[(0x3 & data[i]) << 4];++}++static inline+void sl2_unserialize(sl2_t m, unsigned char buf[86]) {++  int i, j;+  unsigned char a, b, c, d, *data = (unsigned char *)m;++  for (i = j = 0; i <= 86 - 4; i += 4, j += 3) {+    a = unb64[buf[i + 0]];+    b = unb64[buf[i + 1]];+    c = unb64[buf[i + 2]];+    d = unb64[buf[i + 3]];+    data[j + 0] = (a << 2) | (b >> 4);+    data[j + 1] = (b << 4) | (c >> 2);+    data[j + 2] = (c << 6) | (d);+  }++  data[63] = (unb64[buf[i]] << 2) | (unb64[buf[i + 1]] >> 4);++}
− src/gf2p127-inl.h
@@ -1,117 +0,0 @@-#pragma once--#include <stdio.h>-#include <stdint.h>-#include <smmintrin.h>-#include <wmmintrin.h>--typedef __m128i gf2p127_t;--static const inline-_Bool gf2p127_valid(const gf2p127_t a) {-  return (_mm_extract_epi64(a, 1) & (UINT64_C(1) << 63)) == 0;-}--static const inline-_Bool gf2p127_eq(const gf2p127_t a, const gf2p127_t b) {-  _Bool lo = _mm_extract_epi64(a, 0) == _mm_extract_epi64(b, 0);-  _Bool hi = _mm_extract_epi64(a, 1) == _mm_extract_epi64(b, 1);-  return lo && hi;-}--static const inline-gf2p127_t gf2p127_zero() {-  return _mm_setzero_si128();-}--static const inline-gf2p127_t gf2p127_from_int(int a) {-  return _mm_cvtsi32_si128(a);-}--static const inline-gf2p127_t gf2p127_mul_bit(const gf2p127_t a, const _Bool bit) {-  return _mm_slli_epi64(a, !bit * 64);-}--static const inline-gf2p127_t gf2p127_add(const gf2p127_t a, const gf2p127_t b) {-  return _mm_xor_si128(a, b);-}--static const inline-gf2p127_t gf2p127_mul_00(const gf2p127_t a) {-  return _mm_setzero_si128();-}--static const inline-gf2p127_t gf2p127_mul_01(const gf2p127_t a) {-  return a;-}--static const gf2p127_t *minmax __attribute__((__aligned__(16))) =-  (gf2p127_t *)(uint64_t [4]){0, 0, UINT64_MAX, UINT64_MAX};--static const gf2p127_t *x127 __attribute__((__aligned__(16))) =-  (gf2p127_t *)(uint32_t [4]){0, 0, 0, 1 << 31};--static const inline-gf2p127_t gf2p127_mul_10(const gf2p127_t a) {-  // Shift lower and upper halves left by one bit,-  // resembling a multiplication by two.-  gf2p127_t sl = _mm_slli_epi64(a, 1);-  // Check for a x^127 overflow, and add the polynom and carry bit.-  gf2p127_t one = _mm_srli_epi64(_mm_alignr_epi8(a, sl, 8), 63);-  gf2p127_t over = _mm_and_si128(sl, _mm_load_si128(x127));-  gf2p127_t x127x63 = _mm_unpackhi_epi64(over, over);-  return _mm_xor_si128(_mm_xor_si128(sl, one), x127x63);-}--static const inline-gf2p127_t gf2p127_mul_11(const gf2p127_t a) {-  gf2p127_t mul01 = gf2p127_mul_01(a);-  gf2p127_t mul10 = gf2p127_mul_10(a);-  return _mm_xor_si128(mul01, mul10);-};--static const inline-gf2p127_t gf2p127_mul(const gf2p127_t a, const gf2p127_t b) {-  gf2p127_t tmp, lo, hi;--  // Multiplication (Karatsuba):-  //   tmp <- (a0 + a1) * (b0 + b1)-  tmp = _mm_xor_si128(_mm_unpacklo_epi64(a, b), _mm_unpackhi_epi64(a, b));-  tmp = _mm_clmulepi64_si128(tmp, tmp, 0x10);-  //   lo <- a0 * b0-  lo = _mm_clmulepi64_si128(a, b, 0x00);-  //   hi <- a1 * b1-  hi = _mm_clmulepi64_si128(a, b, 0x11);-  //   tmp <- (a0 + a1) * (b0 + b1) + a0 * b0 + a1 * b1-  tmp = _mm_xor_si128(tmp, _mm_xor_si128(lo, hi));-  //   lo <- a0 * b0 + low64[(a0 + a1) * (b0 + b1) + a0 * b0 + a1 * b1] * x^64-  lo = _mm_xor_si128(lo, _mm_slli_si128(tmp, 8));-  //   hi <- a1 * b1 + high64[(a0 + a1) * (b0 + b1) + a0 * b0 + a1 * b1]-  hi = _mm_xor_si128(hi, _mm_srli_si128(tmp, 8));--  // Reduction (modulo f(x) = x^127 + x^63 + 1)-  //   tmp <- low64[hi] * x^64 + high64[lo]-  tmp = _mm_alignr_epi8(hi, lo, 8);-  tmp = _mm_xor_si128(tmp, hi);-  hi = _mm_slli_epi64(hi, 1);-  lo = _mm_xor_si128(lo, hi);-  hi = _mm_unpackhi_epi64(hi, tmp);-  lo = _mm_xor_si128(lo, hi);-  tmp = _mm_srli_epi64(tmp, 63);-  lo = _mm_xor_si128(lo, tmp);-  hi = _mm_unpacklo_epi64(tmp, tmp);-  lo = _mm_xor_si128(lo, _mm_slli_epi64(hi, 63));--  return lo;-}--static inline-char *gf2p127_hex(char *str, const gf2p127_t m) {-  sprintf(str, "%.16llx%.16llx", _mm_extract_epi64(m, 1),-                                 _mm_extract_epi64(m, 0));-  return str;-}
− src/sl2-inl.h
@@ -1,225 +0,0 @@-#pragma once--#include "gf2p127-inl.h"--typedef gf2p127_t sl2_t[2][2] __attribute__((__aligned__(16)));--static inline-_Bool sl2_valid(sl2_t a) {-  gf2p127_t det = gf2p127_add(gf2p127_mul(a[0][0], a[1][1]),-                              gf2p127_mul(a[0][1], a[1][0]));-  return _mm_extract_epi64(det, 0) == 1 &&-         _mm_extract_epi64(det, 1) == 0 &&-         gf2p127_valid(a[0][0]) &&-         gf2p127_valid(a[0][1]) &&-         gf2p127_valid(a[1][0]) &&-         gf2p127_valid(a[1][1]);-}--static inline-_Bool sl2_eq(sl2_t a, sl2_t b) {-  return gf2p127_eq(a[0][0], b[0][0]) &&-         gf2p127_eq(a[0][1], b[0][1]) &&-         gf2p127_eq(a[1][0], b[1][0]) &&-         gf2p127_eq(a[1][1], b[1][1]);-}--static inline-void sl2_copy(sl2_t dst, sl2_t src) {-  dst[0][0] = src[0][0];-  dst[0][1] = src[0][1];-  dst[1][0] = src[1][0];-  dst[1][1] = src[1][1];-}--static inline-void sl2_mul_bit_left(gf2p127_t *b00, gf2p127_t *b01, gf2p127_t *b10, gf2p127_t *b11, gf2p127_t bits) {-  // A: {00 = 10, 01 = 01, 10 = 01, 11 = 00}-  // B: {00 = 10, 01 = 11, 10 = 01, 11 = 01}-  gf2p127_t b10_ = *b10;-  gf2p127_t b11_ = *b11;-  *b10 = gf2p127_add(*b00, _mm_and_si128(*b10, bits));-  *b11 = gf2p127_add(*b01, _mm_and_si128(*b11, bits));-  *b00 = gf2p127_add(b10_, gf2p127_mul_10(*b10));-  *b01 = gf2p127_add(b11_, gf2p127_mul_10(*b11));-}--static inline-void sl2_mul_bits_left(gf2p127_t *b00, gf2p127_t *b01, gf2p127_t *b10, gf2p127_t *b11, unsigned char byte) {-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 0) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 1) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 2) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 3) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 4) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 5) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 6) & 1]));-  sl2_mul_bit_left(b00, b01, b10, b11, _mm_load_si128(&minmax[(byte >> 7) & 1]));-}--static inline-void sl2_mul_buf_left(sl2_t b, unsigned char *buf, size_t n) {-  gf2p127_t b00 = b[0][0];-  gf2p127_t b01 = b[0][1];-  gf2p127_t b10 = b[1][0];-  gf2p127_t b11 = b[1][1];-  size_t i;-  for (i = n; i > 0; i--) {-    sl2_mul_bits_left(&b00, &b01, &b10, &b11, buf[i - 1]);-  }-  b[0][0] = b00;-  b[0][1] = b01;-  b[1][0] = b10;-  b[1][1] = b11;-}--static inline-void sl2_mul_bit_right(gf2p127_t *a00, gf2p127_t *a01, gf2p127_t *a10, gf2p127_t *a11, gf2p127_t bits) {-  // A: {00 = 10, 01 = 01, 10 = 01, 11 = 00}-  // B: {00 = 10, 01 = 11, 10 = 01, 11 = 01}-  gf2p127_t a00_ = *a00;-  gf2p127_t a10_ = *a10;-  *a00 = gf2p127_add(gf2p127_mul_10(*a00), *a01);-  *a10 = gf2p127_add(gf2p127_mul_10(*a10), *a11);-  *a01 = gf2p127_add(a00_, _mm_and_si128(*a00, bits));-  *a11 = gf2p127_add(a10_, _mm_and_si128(*a10, bits));-}--static inline-void sl2_mul_bits_right(gf2p127_t *a00, gf2p127_t *a01, gf2p127_t *a10, gf2p127_t *a11, unsigned char byte) {-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 7) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 6) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 5) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 4) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 3) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 2) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 1) & 1]));-  sl2_mul_bit_right(a00, a01, a10, a11, _mm_load_si128(&minmax[(byte >> 0) & 1]));-}--static inline-void sl2_mul_buf_right(sl2_t a, unsigned char *buf, size_t n) {-  gf2p127_t a00 = _mm_load_si128(&a[0][0]);-  gf2p127_t a01 = _mm_load_si128(&a[0][1]);-  gf2p127_t a10 = _mm_load_si128(&a[1][0]);-  gf2p127_t a11 = _mm_load_si128(&a[1][1]);-  size_t i;-  for (i = 0; i < n; i++) {-    sl2_mul_bits_right(&a00, &a01, &a10, &a11, buf[i]);-  }-  a[0][0] = a00;-  a[0][1] = a01;-  a[1][0] = a10;-  a[1][1] = a11;-}--static inline-void sl2_mul(sl2_t c, sl2_t a, sl2_t b) {-  // Strassen algorithm-  gf2p127_t m0, m1, m2, m3, m4, m5, m6;-  m0 = gf2p127_mul(gf2p127_add(a[0][0], a[1][1]),-                   gf2p127_add(b[0][0], b[1][1]));-  m1 = gf2p127_mul(gf2p127_add(a[1][0], a[1][1]), b[0][0]);-  m2 = gf2p127_mul(a[0][0], gf2p127_add(b[0][1], b[1][1]));-  m3 = gf2p127_mul(a[1][1], gf2p127_add(b[1][0], b[0][0]));-  m4 = gf2p127_mul(gf2p127_add(a[0][0], a[0][1]), b[1][1]);-  m5 = gf2p127_mul(gf2p127_add(a[1][0], a[0][0]),-                   gf2p127_add(b[0][0], b[0][1]));-  m6 = gf2p127_mul(gf2p127_add(a[0][1], a[1][1]),-                   gf2p127_add(b[1][0], b[1][1]));-  c[0][0] = gf2p127_add(gf2p127_add(m0, m3), gf2p127_add(m4, m6));-  c[0][1] = gf2p127_add(m2, m4);-  c[1][0] = gf2p127_add(m1, m3);-  c[1][1] = gf2p127_add(gf2p127_add(m0, m1), gf2p127_add(m2, m5));-}--static inline-void sl2_mul_byte_left(sl2_t b, unsigned char byte, sl2_t m[256]) {-  sl2_mul(m[byte], b, b);-}--static inline-void sl2_mul_byte_right(sl2_t a, unsigned char byte, sl2_t m[256]) {-  sl2_mul(a, m[byte], a);-}--static inline-void sl2_init(sl2_t m[2]) {-  m[0][0][0] = gf2p127_from_int(2);-  m[0][0][1] = gf2p127_from_int(1);-  m[0][1][0] = gf2p127_from_int(1);-  m[0][1][1] = gf2p127_from_int(0);-  m[1][0][0] = gf2p127_from_int(2);-  m[1][0][1] = gf2p127_from_int(3);-  m[1][1][0] = gf2p127_from_int(1);-  m[1][1][1] = gf2p127_from_int(1);-}--static inline-void sl2_unit(sl2_t a) {-  a[0][0] = gf2p127_from_int(1);-  a[0][1] = gf2p127_from_int(0);-  a[1][0] = gf2p127_from_int(0);-  a[1][1] = gf2p127_from_int(1);-}--static inline-char *sl2_hex(char *buf, sl2_t a) {-  gf2p127_hex(&buf[0],  a[0][0]);-  gf2p127_hex(&buf[32], a[0][1]);-  gf2p127_hex(&buf[64], a[1][0]);-  gf2p127_hex(&buf[96], a[1][1]);-  return buf;-}--static const unsigned char b64[64] =-  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";--static const unsigned char unb64[256] = {-  ['A'] =  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12,-          13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,-  ['a'] = 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,-  ['0'] = 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,-  ['-'] = 62, ['_'] = 63-};--static inline-void sl2_serialize(sl2_t m, unsigned char buf[86]) {--  int i, j;-  unsigned char a, b, c, *data = (unsigned char *)m;--  for (i = j = 0; i <= 64 - 3; i += 3, j += 4) {-    a = data[i + 0];-    b = data[i + 1];-    c = data[i + 2];-    buf[j + 0] = b64[a >> 2];-    buf[j + 1] = b64[((0x03 & a) << 4) + (b >> 4)];-    buf[j + 2] = b64[((0x0f & b) << 2) + (c >> 6)];-    buf[j + 3] = b64[0x3f & c];-  }--  buf[84] = b64[data[i] >> 2];-  buf[85] = b64[(0x3 & data[i]) << 4];--}--static inline-void sl2_unserialize(sl2_t m, unsigned char buf[86]) {--  int i, j;-  unsigned char a, b, c, d, *data = (unsigned char *)m;--  for (i = j = 0; i <= 86 - 4; i += 4, j += 3) {-    a = unb64[buf[i + 0]];-    b = unb64[buf[i + 1]];-    c = unb64[buf[i + 2]];-    d = unb64[buf[i + 3]];-    data[j + 0] = (a << 2) | (b >> 4);-    data[j + 1] = (b << 4) | (c >> 2);-    data[j + 2] = (c << 6) | (d);-  }--  data[63] = (unb64[buf[i]] << 2) | (unb64[buf[i + 1]] >> 4);--}