philbin 1.0.1

A pure Rust AEGIS library with SIMD and runtime CPU detection
Documentation
#![cfg(target_arch = "x86_64")]

use crate::arch::{HasSse2, Simd, with_simd};
use crate::base::block::{
  Array128, Block, gen_shared_block128, gen_shared_block256,
  gen_shared_block512,
};
use std::arch::x86_64::*;
use std::ops::{BitAnd, BitXor};
use zerocopy::transmute;

/// A 128-bit SIMD vector using SSE2 and AES-NI.
#[derive(Clone, Copy)]
pub struct Sse1x128<S: Simd> {
  val: __m128i,
  simd: S,
}

impl<S: Simd> Block for Sse1x128<S>
where
  S: HasSse2,
{
  gen_shared_block128!(S);

  #[inline(always)]
  fn aes_encrypt_round(state: Self, round_key: Self) -> Self {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        state: __m128i,
        round_key: __m128i
      ) -> __m128i {
        _mm_aesenc_si128(state, round_key)
      }
    }

    Self {
      val: helper(state.simd, state.val, round_key.val),
      simd: state.simd,
    }
  }
}

impl<S: Simd> BitAnd for Sse1x128<S>
where
  S: HasSse2,
{
  type Output = Sse1x128<S>;

  #[inline(always)]
  fn bitand(self, rhs: Self) -> Self::Output {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        first: __m128i,
        second: __m128i
      ) -> __m128i {
        _mm_and_si128(first, second)
      }
    }

    Self {
      val: helper(self.simd, self.val, rhs.val),
      simd: self.simd,
    }
  }
}

impl<S: Simd> BitXor for Sse1x128<S>
where
  S: HasSse2,
{
  type Output = Sse1x128<S>;

  #[inline(always)]
  fn bitxor(self, rhs: Self) -> Self::Output {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        first: __m128i,
        second: __m128i
      ) -> __m128i {
        _mm_xor_si128(first, second)
      }
    }

    Self {
      val: helper(self.simd, self.val, rhs.val),
      simd: self.simd,
    }
  }
}

/// A 256-bit SIMD vector using SSE2 and AES-NI.
#[derive(Clone, Copy)]
pub struct Sse2x128<S: Simd> {
  val: [__m128i; 2],
  simd: S,
}

impl<S: Simd> Block for Sse2x128<S>
where
  S: HasSse2,
{
  gen_shared_block256!(S);

  fn xor_down(self) -> Array128 {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        input: [__m128i; 2]
      ) -> Array128 {
        transmute!(_mm_xor_si128(input[0], input[1]))
      }
    }

    helper(self.simd, self.val)
  }

  fn aes_encrypt_round(state: Self, round_key: Self) -> Self {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        state: [__m128i; 2],
        round_key: [__m128i; 2],
      ) -> [__m128i; 2] {
        [
          _mm_aesenc_si128(state[0], round_key[0]),
          _mm_aesenc_si128(state[1], round_key[1]),
        ]
      }
    }

    Self {
      val: helper(state.simd, state.val, round_key.val),
      simd: state.simd,
    }
  }
}

impl<S: Simd> BitAnd for Sse2x128<S>
where
  S: HasSse2,
{
  type Output = Sse2x128<S>;

  #[inline(always)]
  fn bitand(self, rhs: Self) -> Self::Output {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        first: [__m128i; 2],
        second: [__m128i; 2],
      ) -> [__m128i; 2]{
        [
          _mm_and_si128(first[0], second[0]),
          _mm_and_si128(first[1], second[1]),
        ]
      }
    }

    Self {
      val: helper(self.simd, self.val, rhs.val),
      simd: self.simd,
    }
  }
}

impl<S: Simd> BitXor for Sse2x128<S>
where
  S: HasSse2,
{
  type Output = Sse2x128<S>;

  #[inline(always)]
  fn bitxor(self, rhs: Self) -> Self::Output {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        first: [__m128i; 2],
        second: [__m128i; 2],
      ) -> [__m128i; 2]{
        [
          _mm_xor_si128(first[0], second[0]),
          _mm_xor_si128(first[1], second[1]),
        ]
      }
    }

    Self {
      val: helper(self.simd, self.val, rhs.val),
      simd: self.simd,
    }
  }
}

/// A 512-bit SIMD vector using SSE2 and AES-NI.
#[derive(Clone, Copy)]
pub struct Sse4x128<S: Simd> {
  val: [__m128i; 4],
  simd: S,
}

impl<S: Simd> Block for Sse4x128<S>
where
  S: HasSse2,
{
  gen_shared_block512!(S);

  fn xor_down(self) -> Array128 {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        input: [__m128i; 4]
      ) -> Array128 {
        // 512 bit vec can be seen as 4x128: (a, b, c, d)
        // (a ^ c) ^ (b ^ d) == a ^ b ^ c ^ d
        let temp1 = _mm_xor_si128(input[0], input[1]);
        let temp2 = _mm_xor_si128(input[2], input[3]);
        let out = _mm_xor_si128(temp1, temp2);
        transmute!(out)
      }
    }

    helper(self.simd, self.val)
  }

  fn aes_encrypt_round(state: Self, round_key: Self) -> Self {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        state: [__m128i; 4],
        round_key: [__m128i; 4],
      ) -> [__m128i; 4] {
        [
          _mm_aesenc_si128(state[0], round_key[0]),
          _mm_aesenc_si128(state[1], round_key[1]),
          _mm_aesenc_si128(state[2], round_key[2]),
          _mm_aesenc_si128(state[3], round_key[3]),
        ]
      }
    }

    Self {
      val: helper(state.simd, state.val, round_key.val),
      simd: state.simd,
    }
  }
}

impl<S: Simd> BitAnd for Sse4x128<S>
where
  S: HasSse2,
{
  type Output = Sse4x128<S>;

  #[inline(always)]
  fn bitand(self, rhs: Self) -> Self::Output {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        first: [__m128i; 4],
        second: [__m128i; 4],
      ) -> [__m128i; 4]{
        [
          _mm_and_si128(first[0], second[0]),
          _mm_and_si128(first[1], second[1]),
          _mm_and_si128(first[2], second[2]),
          _mm_and_si128(first[3], second[3]),
        ]
      }
    }

    Self {
      val: helper(self.simd, self.val, rhs.val),
      simd: self.simd,
    }
  }
}

impl<S: Simd> BitXor for Sse4x128<S>
where
  S: HasSse2,
{
  type Output = Sse4x128<S>;

  #[inline(always)]
  fn bitxor(self, rhs: Self) -> Self::Output {
    with_simd! {
      fn helper(
        token: impl HasSse2,
        first: [__m128i; 4],
        second: [__m128i; 4],
      ) -> [__m128i; 4]{
        [
          _mm_xor_si128(first[0], second[0]),
          _mm_xor_si128(first[1], second[1]),
          _mm_xor_si128(first[2], second[2]),
          _mm_xor_si128(first[3], second[3]),
        ]
      }
    }

    Self {
      val: helper(self.simd, self.val, rhs.val),
      simd: self.simd,
    }
  }
}