philbin 1.0.1

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

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

/// A 512-bit SIMD vector using AVX-512.
#[derive(Clone, Copy)]
pub struct Avx1x512<S: Simd> {
  val: __m512i,
  simd: S,
}

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

  fn xor_down(self) -> Array128 {
    with_simd! {
      fn helper(
        token: impl HasAvx512,
        input: __m512i,
      ) -> Array128 {
        // 512 bit vec can be seen as 4x128: (a, b, c, d)
        //
        // (a || b) ^ (c || d) -> (a ^ c) || (b ^ d)

        // NOTE: _mm512_castsi512_si256_(x) is identical to, yet cheaper than,
        // _mm512_extracti64x4_epi64(x, 0).
        let low_256 = _mm512_castsi512_si256(input);
        let high_256 = _mm512_extracti64x4_epi64(input, 1);
        let temp = _mm256_xor_si256(low_256, high_256);

        // (a ^ c) ^ (b ^ d) == a ^ b ^ c ^ d

        // NOTE: _mm256_castsi256_si128(x) is identical to, yet cheaper than,
        // _mm256_extracti128_si256(x, 0).
        let low_128 = _mm256_castsi256_si128(temp);
        let high_128 = _mm256_extracti128_si256(temp, 1);
        let out = _mm_xor_si128(low_128, high_128);
        transmute!(out)
      }
    }

    helper(self.simd, self.val)
  }

  fn aes_encrypt_round(state: Self, round_key: Self) -> Self {
    with_simd! {
      fn helper(
        token: impl HasAvx512,
        state: __m512i,
        round_key: __m512i
      ) -> __m512i {
        _mm512_aesenc_epi128(state, round_key)
      }
    }

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

impl<S: Simd> BitAnd for Avx1x512<S>
where
  S: HasAvx512,
{
  type Output = Avx1x512<S>;

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

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

impl<S: Simd> BitXor for Avx1x512<S>
where
  S: HasAvx512,
{
  type Output = Avx1x512<S>;

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

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