xref: /freebsd/crypto/libecc/include/libecc/words/words.h (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2017 - This file is part of libecc project
3  *
4  *  Authors:
5  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7  *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8  *
9  *  Contributors:
10  *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11  *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12  *
13  *  This software is licensed under a dual BSD and GPL v2 license.
14  *  See LICENSE file at the root folder of the project.
15  */
16 #ifndef __WORDS_H__
17 #define __WORDS_H__
18 
19 /*
20  * Types for words and a few useful macros.
21  */
22 
23 /*
24  * If a word size is forced, we use the proper words.h definition.
25  * By default, 64-bit word size is used since it is the most reasonable
26  * choice across the known platforms (see below).
27  */
28 
29 #define __concat(x) #x
30 #define _concat(file_prefix, x) __concat(file_prefix##x.h)
31 #define concat(file_prefix, x) _concat(file_prefix, x)
32 
33 #if defined(WORDSIZE)
34 	/* The word size is forced by the compilation chain */
35 #if (WORDSIZE == 16) || (WORDSIZE == 32) || (WORDSIZE == 64)
36 	/* Dynamic include depending on the word size */
37 #include concat(words_, WORDSIZE)
38 #else
39 #error Unsupported word size concat
40 #endif
41 #else
42 /* The word size is usually deduced from the known platforms.
43  * By default when we have fast builtin uint64_t operations,
44  * we use WORDSIZE=64. This is obviously the case on 64-bit platforms,
45  * but this should also be the case on most 32-bit platforms where
46  * native instructions allow a 32-bit x 32-bit to 64-bit multiplication.
47  *
48  * There might however be some platforms where this is not the case.
49  * Cortex-M0/M0+ for example does not have such a native multiplication
50  * instruction, yielding in slower code for WORDSIZE=64 than for WORDSIZE=32.
51  * This is also the case for old Thumb ARM CPUs (pre Thumb-2).
52  *
53  * On 8-bit and 16-bit platform, we prefer to let the user decide on the best
54  * option (see below)!
55  */
56 #if defined(__x86_64__) || defined(__i386__) || defined(__ppc64__) || defined(__ppc__) ||\
57     defined(__arm__) || defined(__aarch64__) || defined(__mips__) || defined(__s390x__) ||\
58     defined(__SH4__) || defined(__sparc__) || defined(__riscv)
59 #define WORDSIZE 64
60 #include "words_64.h"
61 #else
62 /* We let the user fix the WORDSIZE manually */
63 #error "Unrecognized platform. Please specify the word size of your target (with make 16, make 32, make 64)"
64 #endif /* Unrecognized */
65 #endif
66 
67 typedef uint8_t u8;
68 typedef uint16_t u16;
69 typedef uint32_t u32;
70 typedef uint64_t u64;
71 typedef u16 bitcnt_t;
72 
73 /*
74  * Shift behavior is not defined for a shift count
75  * higher than (WORD_BITS - 1). These macros emulate
76  * the behavior one would expect, i.e. return 0 when
77  * shift count is equal or more than word size.
78  */
79 #define WLSHIFT(w, c) ((word_t)(((c) >= WORD_BITS) ? WORD(0) : (word_t)((w) << (c))))
80 #define WRSHIFT(w, c) ((word_t)(((c) >= WORD_BITS) ? WORD(0) : (word_t)((w) >> (c))))
81 
82 /* To be fixed: not really constant-time. */
83 #define WORD_MIN(a, b) ((a) > (b) ? (b) : (a))
84 
85 /* WORD_MASK[_IF[NOT]ZERO]: mask of word size and associated macros. */
86 #define WORD_MASK WORD_MAX
87 
88 /* These two macros assume two-complement representation. */
89 #define WORD_MASK_IFZERO(w) ((word_t)(((word_t)((w) != 0)) - WORD(1)))
90 #define WORD_MASK_IFNOTZERO(w) ((word_t)(((word_t)((w) == 0)) - WORD(1)))
91 
92 #define HWORD_MASK HWORD_MAX
93 
94 /* WORD_HIGHBIT: constant of word size with only MSB set. */
95 #define WORD_HIGHBIT (WORD(1) << (WORD_BITS - 1))
96 
97 /* WORD_MUL: multiply two words using schoolbook multiplication on half words */
98 #define WORD_MUL(outh, outl, in1, in2) do {				\
99 	word_t in1h, in1l, in2h, in2l;					\
100 	word_t tmph, tmpm, tmpl;					\
101 	word_t tmpm1, tmpm2;						\
102 	word_t carrym, carryl;						\
103 	/* Get high and low half words. */				\
104 	in1h = (in1) >> HWORD_BITS;					\
105 	in1l = (in1) & HWORD_MASK;					\
106 	in2h = (in2) >> HWORD_BITS;					\
107 	in2l = (in2) & HWORD_MASK;					\
108 	/* Compute low product. */					\
109 	tmpl = (word_t)(in2l * in1l);					\
110 	/* Compute middle product. */					\
111 	tmpm1 = (word_t)(in2h * in1l);					\
112 	tmpm2 = (word_t)(in2l * in1h);					\
113 	tmpm = (word_t)(tmpm1 + tmpm2);					\
114 	/* Store middle product carry. */				\
115 	carrym = (word_t)(tmpm < tmpm1);				\
116 	/* Compute full low product. */					\
117 	(outl) = tmpl;							\
118 	(outl) = (word_t)((outl) + ((tmpm & HWORD_MASK) << HWORD_BITS));\
119 	/* Store full low product carry. */				\
120 	carryl = (word_t)((outl) < tmpl);				\
121 	/* Compute full high product. */				\
122 	carryl = (word_t)(carryl + (tmpm >> HWORD_BITS));		\
123 	carryl = (word_t)(carryl + (carrym << HWORD_BITS));		\
124 	tmph = (word_t)(in2h * in1h);					\
125 	/* No carry can occur below. */					\
126 	(outh) = (word_t)(tmph + carryl);				\
127 	} while (0)
128 
129 #endif /* __WORDS_H__ */
130