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