1 /* ===================================================================
2 *
3 * Copyright (c) 2018, Helder Eijs <helderijs@gmail.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 * ===================================================================
30 */
31
32 #ifndef ENDIANESS_H
33 #define ENDIANESS_H
34
35 #include "common.h"
36
u32to8_little(uint8_t * p,const uint32_t * w)37 static inline void u32to8_little(uint8_t *p, const uint32_t *w)
38 {
39 #ifdef PYCRYPTO_LITTLE_ENDIAN
40 memcpy(p, w, 4);
41 #else
42 p[0] = (uint8_t)*w;
43 p[1] = (uint8_t)(*w >> 8);
44 p[2] = (uint8_t)(*w >> 16);
45 p[3] = (uint8_t)(*w >> 24);
46 #endif
47 }
48
u8to32_little(uint32_t * w,const uint8_t * p)49 static inline void u8to32_little(uint32_t *w, const uint8_t *p)
50 {
51 #ifdef PYCRYPTO_LITTLE_ENDIAN
52 memcpy(w, p, 4);
53 #else
54 *w = (uint32_t)p[0] | (uint32_t)p[1]<<8 | (uint32_t)p[2]<<16 | (uint32_t)p[3]<<24;
55 #endif
56 }
57
u32to8_big(uint8_t * p,const uint32_t * w)58 static inline void u32to8_big(uint8_t *p, const uint32_t *w)
59 {
60 #ifdef PYCRYPTO_BIG_ENDIAN
61 memcpy(p, w, 4);
62 #else
63 p[0] = (uint8_t)(*w >> 24);
64 p[1] = (uint8_t)(*w >> 16);
65 p[2] = (uint8_t)(*w >> 8);
66 p[3] = (uint8_t)*w;
67 #endif
68 }
69
u8to32_big(uint32_t * w,const uint8_t * p)70 static inline void u8to32_big(uint32_t *w, const uint8_t *p)
71 {
72 #ifdef PYCRYPTO_BIG_ENDIAN
73 memcpy(w, p, 4);
74 #else
75 *w = (uint32_t)p[3] | (uint32_t)p[2]<<8 | (uint32_t)p[1]<<16 | (uint32_t)p[0]<<24;
76 #endif
77 }
78
load_u8to32_little(const uint8_t * p)79 static inline uint32_t load_u8to32_little(const uint8_t *p)
80 {
81 uint32_t w;
82
83 u8to32_little(&w, p);
84 return w;
85 }
86
load_u8to32_big(const uint8_t * p)87 static inline uint32_t load_u8to32_big(const uint8_t *p)
88 {
89 uint32_t w;
90
91 u8to32_big(&w, p);
92 return w;
93 }
94
95 #define LOAD_U32_LITTLE(p) load_u8to32_little(p)
96 #define LOAD_U32_BIG(p) load_u8to32_big(p)
97
98 #define STORE_U32_LITTLE(p, w) u32to8_little((p), &(w))
99 #define STORE_U32_BIG(p, w) u32to8_big((p), &(w))
100
u64to8_little(uint8_t * p,const uint64_t * w)101 static inline void u64to8_little(uint8_t *p, const uint64_t *w)
102 {
103 #ifdef PYCRYPTO_LITTLE_ENDIAN
104 memcpy(p, w, 8);
105 #else
106 p[0] = (uint8_t)*w;
107 p[1] = (uint8_t)(*w >> 8);
108 p[2] = (uint8_t)(*w >> 16);
109 p[3] = (uint8_t)(*w >> 24);
110 p[4] = (uint8_t)(*w >> 32);
111 p[5] = (uint8_t)(*w >> 40);
112 p[6] = (uint8_t)(*w >> 48);
113 p[7] = (uint8_t)(*w >> 56);
114 #endif
115 }
116
u8to64_little(uint64_t * w,const uint8_t * p)117 static inline void u8to64_little(uint64_t *w, const uint8_t *p)
118 {
119 #ifdef PYCRYPTO_LITTLE_ENDIAN
120 memcpy(w, p, 8);
121 #else
122 *w = (uint64_t)p[0] |
123 (uint64_t)p[1] << 8 |
124 (uint64_t)p[2] << 16 |
125 (uint64_t)p[3] << 24 |
126 (uint64_t)p[4] << 32 |
127 (uint64_t)p[5] << 40 |
128 (uint64_t)p[6] << 48 |
129 (uint64_t)p[7] << 56;
130 #endif
131 }
132
u64to8_big(uint8_t * p,const uint64_t * w)133 static inline void u64to8_big(uint8_t *p, const uint64_t *w)
134 {
135 #ifdef PYCRYPTO_BIG_ENDIAN
136 memcpy(p, w, 8);
137 #else
138 p[0] = (uint8_t)(*w >> 56);
139 p[1] = (uint8_t)(*w >> 48);
140 p[2] = (uint8_t)(*w >> 40);
141 p[3] = (uint8_t)(*w >> 32);
142 p[4] = (uint8_t)(*w >> 24);
143 p[5] = (uint8_t)(*w >> 16);
144 p[6] = (uint8_t)(*w >> 8);
145 p[7] = (uint8_t)*w;
146 #endif
147 }
148
u8to64_big(uint64_t * w,const uint8_t * p)149 static inline void u8to64_big(uint64_t *w, const uint8_t *p)
150 {
151 #ifdef PYCRYPTO_BIG_ENDIAN
152 memcpy(w, p, 8);
153 #else
154 *w = (uint64_t)p[0] << 56 |
155 (uint64_t)p[1] << 48 |
156 (uint64_t)p[2] << 40 |
157 (uint64_t)p[3] << 32 |
158 (uint64_t)p[4] << 24 |
159 (uint64_t)p[5] << 16 |
160 (uint64_t)p[6] << 8 |
161 (uint64_t)p[7];
162 #endif
163 }
164
load_u8to64_little(const uint8_t * p)165 static inline uint64_t load_u8to64_little(const uint8_t *p)
166 {
167 uint64_t w;
168
169 u8to64_little(&w, p);
170 return w;
171 }
172
load_u8to64_big(const uint8_t * p)173 static inline uint64_t load_u8to64_big(const uint8_t *p)
174 {
175 uint64_t w;
176
177 u8to64_big(&w, p);
178 return w;
179 }
180
181 #define LOAD_U64_LITTLE(p) load_u8to64_little(p)
182 #define LOAD_U64_BIG(p) load_u8to64_big(p)
183
184 #define STORE_U64_LITTLE(p, w) u64to8_little((p), &(w))
185 #define STORE_U64_BIG(p, w) u64to8_big((p), &(w))
186
187 /**
188 * Convert a big endian-encoded number in[] into a little-endian
189 * 64-bit word array x[]. There must be enough words to contain the entire
190 * number.
191 */
bytes_to_words(uint64_t * x,size_t words,const uint8_t * in,size_t len)192 static inline int bytes_to_words(uint64_t *x, size_t words, const uint8_t *in, size_t len)
193 {
194 uint8_t buf8[8];
195 size_t words_used, bytes_in_msw, i;
196 uint64_t *xp;
197
198 if (0 == words || 0 == len)
199 return ERR_NOT_ENOUGH_DATA;
200 if (NULL == x || NULL == in)
201 return ERR_NULL;
202
203 memset(x, 0, words*sizeof(uint64_t));
204
205 /** Shorten the input **/
206 for (; len > 0 && 0 == *in; in++, len--);
207 if (0 == len)
208 return 0;
209
210 /** How many words we actually need **/
211 words_used = (len + 7) / 8;
212 if (words_used > words)
213 return ERR_MAX_DATA;
214
215 /** Not all bytes in the most-significant words are used **/
216 bytes_in_msw = len % 8;
217 if (bytes_in_msw == 0)
218 bytes_in_msw = 8;
219
220 /** Do most significant word **/
221 memset(buf8, 0, 8);
222 memcpy(buf8 + (8 - bytes_in_msw), in, bytes_in_msw);
223 xp = &x[words_used-1];
224 *xp = LOAD_U64_BIG(buf8);
225 in += bytes_in_msw;
226
227 /** Do the other words **/
228 for (i=0; i<words_used-1; i++, in += 8) {
229 xp--;
230 *xp = LOAD_U64_BIG(in);
231 }
232 return 0;
233 }
234
235 /**
236 * Convert a little-endian 64-bit word array x[] into a big endian-encoded
237 * number out[]. The number is left-padded with zeroes if required.
238 */
words_to_bytes(uint8_t * out,size_t len,const uint64_t * x,size_t words)239 static inline int words_to_bytes(uint8_t *out, size_t len, const uint64_t *x, size_t words)
240 {
241 size_t i;
242 const uint64_t *msw;
243 uint8_t buf8[8];
244 size_t partial, real_len;
245
246 if (0 == words || 0 == len)
247 return ERR_NOT_ENOUGH_DATA;
248 if (NULL == x || NULL == out)
249 return ERR_NULL;
250
251 memset(out, 0, len);
252
253 /* Shorten the input, so that the rightmost word is
254 * the most significant one (and non-zero)
255 */
256 for (; words>0 && x[words-1]==0; words--);
257 if (words == 0)
258 return 0;
259 msw = &x[words-1];
260
261 /* Find how many non-zero bytes there are in the most-significant word */
262 STORE_U64_BIG(buf8, *msw);
263 for (partial=8; partial>0 && buf8[8-partial] == 0; partial--);
264 assert(partial > 0);
265
266 /** Check if there is enough room **/
267 real_len = partial + 8*(words-1);
268 if (real_len > len)
269 return ERR_MAX_DATA;
270
271 /** Pad **/
272 out += len - real_len;
273
274 /** Most significant word **/
275 memcpy(out, buf8+(8-partial), partial);
276 out += partial;
277 msw--;
278
279 /** Any remaining full word **/
280 for (i=0; i<words-1; i++, out += 8, msw--)
281 STORE_U64_BIG(out, *msw);
282
283 return 0;
284 }
285
286 #endif
287