root/crypto/libecc/include/libecc/words/words.h
/*
 *  Copyright (C) 2017 - This file is part of libecc project
 *
 *  Authors:
 *      Ryad BENADJILA <ryadbenadjila@gmail.com>
 *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
 *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
 *
 *  Contributors:
 *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
 *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
 *
 *  This software is licensed under a dual BSD and GPL v2 license.
 *  See LICENSE file at the root folder of the project.
 */
#ifndef __WORDS_H__
#define __WORDS_H__

/*
 * Types for words and a few useful macros.
 */

/*
 * If a word size is forced, we use the proper words.h definition.
 * By default, 64-bit word size is used since it is the most reasonable
 * choice across the known platforms (see below).
 */

#define __concat(x) #x
#define _concat(file_prefix, x) __concat(file_prefix##x.h)
#define concat(file_prefix, x) _concat(file_prefix, x)

#if defined(WORDSIZE)
        /* The word size is forced by the compilation chain */
#if (WORDSIZE == 16) || (WORDSIZE == 32) || (WORDSIZE == 64)
        /* Dynamic include depending on the word size */
#include concat(words_, WORDSIZE)
#else
#error Unsupported word size concat
#endif
#else
/* The word size is usually deduced from the known platforms.
 * By default when we have fast builtin uint64_t operations,
 * we use WORDSIZE=64. This is obviously the case on 64-bit platforms,
 * but this should also be the case on most 32-bit platforms where
 * native instructions allow a 32-bit x 32-bit to 64-bit multiplication.
 *
 * There might however be some platforms where this is not the case.
 * Cortex-M0/M0+ for example does not have such a native multiplication
 * instruction, yielding in slower code for WORDSIZE=64 than for WORDSIZE=32.
 * This is also the case for old Thumb ARM CPUs (pre Thumb-2).
 *
 * On 8-bit and 16-bit platform, we prefer to let the user decide on the best
 * option (see below)!
 */
#if defined(__x86_64__) || defined(__i386__) || defined(__ppc64__) || defined(__ppc__) ||\
    defined(__arm__) || defined(__aarch64__) || defined(__mips__) || defined(__s390x__) ||\
    defined(__SH4__) || defined(__sparc__) || defined(__riscv)
#define WORDSIZE 64
#include "words_64.h"
#else
/* We let the user fix the WORDSIZE manually */
#error "Unrecognized platform. Please specify the word size of your target (with make 16, make 32, make 64)"
#endif /* Unrecognized */
#endif

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef u16 bitcnt_t;

/*
 * Shift behavior is not defined for a shift count
 * higher than (WORD_BITS - 1). These macros emulate
 * the behavior one would expect, i.e. return 0 when
 * shift count is equal or more than word size.
 */
#define WLSHIFT(w, c) ((word_t)(((c) >= WORD_BITS) ? WORD(0) : (word_t)((w) << (c))))
#define WRSHIFT(w, c) ((word_t)(((c) >= WORD_BITS) ? WORD(0) : (word_t)((w) >> (c))))

/* To be fixed: not really constant-time. */
#define WORD_MIN(a, b) ((a) > (b) ? (b) : (a))

/* WORD_MASK[_IF[NOT]ZERO]: mask of word size and associated macros. */
#define WORD_MASK WORD_MAX

/* These two macros assume two-complement representation. */
#define WORD_MASK_IFZERO(w) ((word_t)(((word_t)((w) != 0)) - WORD(1)))
#define WORD_MASK_IFNOTZERO(w) ((word_t)(((word_t)((w) == 0)) - WORD(1)))

#define HWORD_MASK HWORD_MAX

/* WORD_HIGHBIT: constant of word size with only MSB set. */
#define WORD_HIGHBIT (WORD(1) << (WORD_BITS - 1))

/* WORD_MUL: multiply two words using schoolbook multiplication on half words */
#define WORD_MUL(outh, outl, in1, in2) do {                             \
        word_t in1h, in1l, in2h, in2l;                                  \
        word_t tmph, tmpm, tmpl;                                        \
        word_t tmpm1, tmpm2;                                            \
        word_t carrym, carryl;                                          \
        /* Get high and low half words. */                              \
        in1h = (in1) >> HWORD_BITS;                                     \
        in1l = (in1) & HWORD_MASK;                                      \
        in2h = (in2) >> HWORD_BITS;                                     \
        in2l = (in2) & HWORD_MASK;                                      \
        /* Compute low product. */                                      \
        tmpl = (word_t)(in2l * in1l);                                   \
        /* Compute middle product. */                                   \
        tmpm1 = (word_t)(in2h * in1l);                                  \
        tmpm2 = (word_t)(in2l * in1h);                                  \
        tmpm = (word_t)(tmpm1 + tmpm2);                                 \
        /* Store middle product carry. */                               \
        carrym = (word_t)(tmpm < tmpm1);                                \
        /* Compute full low product. */                                 \
        (outl) = tmpl;                                                  \
        (outl) = (word_t)((outl) + ((tmpm & HWORD_MASK) << HWORD_BITS));\
        /* Store full low product carry. */                             \
        carryl = (word_t)((outl) < tmpl);                               \
        /* Compute full high product. */                                \
        carryl = (word_t)(carryl + (tmpm >> HWORD_BITS));               \
        carryl = (word_t)(carryl + (carrym << HWORD_BITS));             \
        tmph = (word_t)(in2h * in1h);                                   \
        /* No carry can occur below. */                                 \
        (outh) = (word_t)(tmph + carryl);                               \
        } while (0)

#endif /* __WORDS_H__ */