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 +2/−0
- dist/build/testStub/testStub-tmp/testStub.hs +1/−1
- hwsl2.cabal +37/−25
- src/Data/Hash/SL2.hs +12/−2
- src/Data/Hash/SL2/Benchmark.hs +4/−2
- src/Data/Hash/SL2/Internal.hs +3/−0
- src/Data/Hash/SL2/Mutable.hs +6/−1
- src/Data/Hash/SL2/Test.hs +28/−1
- src/core/gf2p127-inl.h +138/−0
- src/core/sl2-inl.h +330/−0
- src/gf2p127-inl.h +0/−117
- src/sl2-inl.h +0/−225
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.++
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);--}