packages feed

hwsl2-0.3.0.1: src/sl2-inl.h

#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);

}