/***************************************************************************
* Additional implementation of "BIKE: Bit Flipping Key Encapsulation".
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Written by Nir Drucker and Shay Gueron
* AWS Cryptographic Algorithms Group
* (ndrucker@amazon.com, gueron@amazon.com)
*
* The license is detailed in the file LICENSE.md, and applies to this file.
* ***************************************************************************/

#pragma once

#include "cleanup.h"

#ifndef bswap_64
  #define bswap_64(x) __builtin_bswap64(x)
#endif

// Printing values in Little Endian
void print_LE(IN const uint64_t *in, IN const uint32_t bits_num);

// Printing values in Big Endian
void print_BE(IN const uint64_t *in, IN const uint32_t bits_num);

// Printing number is required only in verbose level 2 or above
#if VERBOSE>=2
  #ifdef PRINT_IN_BE
    // Print in Big Endian
    #define print(in, bits_num) print_BE(in, bits_num)
  #else
    // Print in Little Endian
    #define print(in, bits_num) print_LE(in, bits_num)
  #endif
#else
  // No prints at all
  #define print(in, bits_num)
#endif

// Comparing value in a constant time manner
_INLINE_ uint32_t safe_cmp(IN const uint8_t *a,
                           IN const uint8_t *b,
                           IN const uint32_t size)
{
  volatile uint8_t res = 0;

  for(uint32_t i=0; i < size; ++i)
  {
    res |= (a[i] ^ b[i]);
  }

  return (0 == res);
}

// Constant time
_INLINE_ uint32_t iszero(IN const uint8_t *s, IN const uint32_t len)
{
    volatile uint32_t res = 0;
    for (uint64_t i = 0; i < len; i++)
    {
        res |= s[i];
    }
    return (0 == res);
}

// BSR returns ceil(log2(val))
_INLINE_ uint8_t bit_scan_reverse(uint64_t val)
{
    // index is always smaller than 64
    uint8_t index = 0;

    while(val != 0)
    {
        val >>= 1;
        index++;
    }

    return index;
}

// Return 1 if equal 0 otherwise
_INLINE_ uint32_t secure_cmp32(IN const uint32_t v1, IN const uint32_t v2)
{
#if defined(__aarch64__)
    uint32_t res;
    __asm__ __volatile__("cmp  %w1, %w2; \n "
                         "cset %w0, EQ; \n"
                         : "=r" (res)
                         : "r"(v1), "r"(v2)
                         :);
    return res;
#elif defined(__x86_64__) || defined(__i386__)
    uint32_t res;
    __asm__ __volatile__("xor  %%edx, %%edx; \n"
                         "cmp  %1, %2; \n "
                         "sete %%dl; \n"
                         "mov %%edx, %0; \n"
                         : "=r" (res)
                         : "r"(v1), "r"(v2)
                         : "rdx");
    return res;
#else
    // Insecure comparison: The main purpose of secure_cmp32 is to avoid
    // branches and thus to prevent potential side channel attacks. To do that
    // we normally leverage some CPU special instructions such as "sete"
    // (for __x86_64__) and "cset" (for __aarch64__). When dealing with general
    // CPU architectures, the interpretation of the line below is left for the
    // compiler, which may lead to an insecure branch.
    return (v1 == v2 ? 1 : 0);
#endif
}

// Return 0 if v1 < v2, (-1) otherwise
_INLINE_ uint32_t secure_l32_mask(IN const uint32_t v1, IN const uint32_t v2)
{
#if defined(__aarch64__)
    uint32_t res;
    __asm__ __volatile__("cmp  %w1, %w2; \n "
                         "cset %w0, LS; \n"
                         : "=r" (res)
                         : "r"(v1), "r"(v2)
                         :);
    return (res-1);
#elif defined(__x86_64__) || defined(__i386__)
    uint32_t res;
    __asm__ __volatile__("xor  %%edx, %%edx; \n"
                         "cmp  %1, %2; \n "
                         "setl %%dl; \n"
                         "dec %%edx; \n"
                         "mov %%edx, %0; \n"
                         : "=r" (res)
                         : "r"(v2), "r"(v1)
                         : "rdx");
    return res;
#else
    // If v1 >= v2 then the subtraction result is 0^32||(v1-v2)
    // else it will be 1^32||(v2-v1+1). Subsequently, negating the upper
    // 32 bits gives 0 if v1 < v2 and otherwise (-1).
    return ~((uint32_t)(((uint64_t)v1 - (uint64_t)v2) >> 32));
#endif
}

// len is bytes length of in
EXTERNC uint64_t count_ones(IN const uint8_t *in, IN const uint32_t len);
