ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
BigNumberUtil.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "BigNumberUtil.h"
24 #include "utility/EndianUtil.h"
25 #include "utility/LimbUtil.h"
26 #include <string.h>
27 
55 void BigNumberUtil::unpackLE(limb_t *limbs, size_t count,
56  const uint8_t *bytes, size_t len)
57 {
58 #if BIGNUMBER_LIMB_8BIT
59  if (len < count) {
60  memcpy(limbs, bytes, len);
61  memset(limbs + len, 0, count - len);
62  } else {
63  memcpy(limbs, bytes, count);
64  }
65 #elif CRYPTO_LITTLE_ENDIAN
66  count *= sizeof(limb_t);
67  if (len < count) {
68  memcpy(limbs, bytes, len);
69  memset(((uint8_t *)limbs) + len, 0, count - len);
70  } else {
71  memcpy(limbs, bytes, count);
72  }
73 #elif BIGNUMBER_LIMB_16BIT
74  while (count > 0 && len >= 2) {
75  *limbs++ = ((limb_t)(bytes[0])) |
76  (((limb_t)(bytes[1])) << 8);
77  bytes += 2;
78  --count;
79  len -= 2;
80  }
81  if (count > 0 && len == 1) {
82  *limbs++ = ((limb_t)(bytes[0]));
83  --count;
84  }
85  while (count > 0) {
86  *limbs++ = 0;
87  --count;
88  }
89 #elif BIGNUMBER_LIMB_32BIT
90  while (count > 0 && len >= 4) {
91  *limbs++ = ((limb_t)(bytes[0])) |
92  (((limb_t)(bytes[1])) << 8) |
93  (((limb_t)(bytes[2])) << 16) |
94  (((limb_t)(bytes[3])) << 24);
95  bytes += 4;
96  --count;
97  len -= 4;
98  }
99  if (count > 0) {
100  if (len == 3) {
101  *limbs++ = ((limb_t)(bytes[0])) |
102  (((limb_t)(bytes[1])) << 8) |
103  (((limb_t)(bytes[2])) << 16);
104  } else if (len == 2) {
105  *limbs++ = ((limb_t)(bytes[0])) |
106  (((limb_t)(bytes[1])) << 8);
107  } else if (len == 1) {
108  *limbs++ = ((limb_t)(bytes[0]));
109  }
110  --count;
111  }
112  while (count > 0) {
113  *limbs++ = 0;
114  --count;
115  }
116 #endif
117 }
118 
134 void BigNumberUtil::unpackBE(limb_t *limbs, size_t count,
135  const uint8_t *bytes, size_t len)
136 {
137 #if BIGNUMBER_LIMB_8BIT
138  while (count > 0 && len > 0) {
139  --count;
140  --len;
141  *limbs++ = bytes[len];
142  }
143  memset(limbs, 0, count);
144 #elif BIGNUMBER_LIMB_16BIT
145  bytes += len;
146  while (count > 0 && len >= 2) {
147  --count;
148  bytes -= 2;
149  len -= 2;
150  *limbs++ = ((limb_t)(bytes[1])) |
151  (((limb_t)(bytes[0])) << 8);
152  }
153  if (count > 0 && len == 1) {
154  --count;
155  --bytes;
156  *limbs++ = (limb_t)(bytes[0]);
157  }
158  memset(limbs, 0, count * sizeof(limb_t));
159 #elif BIGNUMBER_LIMB_32BIT
160  bytes += len;
161  while (count > 0 && len >= 4) {
162  --count;
163  bytes -= 4;
164  len -= 4;
165  *limbs++ = ((limb_t)(bytes[3])) |
166  (((limb_t)(bytes[2])) << 8) |
167  (((limb_t)(bytes[1])) << 16) |
168  (((limb_t)(bytes[0])) << 24);
169  }
170  if (count > 0) {
171  if (len == 3) {
172  --count;
173  bytes -= 3;
174  *limbs++ = ((limb_t)(bytes[2])) |
175  (((limb_t)(bytes[1])) << 8) |
176  (((limb_t)(bytes[0])) << 16);
177  } else if (len == 2) {
178  --count;
179  bytes -= 2;
180  *limbs++ = ((limb_t)(bytes[1])) |
181  (((limb_t)(bytes[0])) << 8);
182  } else if (len == 1) {
183  --count;
184  --bytes;
185  *limbs++ = (limb_t)(bytes[0]);
186  }
187  }
188  memset(limbs, 0, count * sizeof(limb_t));
189 #endif
190 }
191 
208 void BigNumberUtil::packLE(uint8_t *bytes, size_t len,
209  const limb_t *limbs, size_t count)
210 {
211 #if BIGNUMBER_LIMB_8BIT
212  if (len <= count) {
213  memcpy(bytes, limbs, len);
214  } else {
215  memcpy(bytes, limbs, count);
216  memset(bytes + count, 0, len - count);
217  }
218 #elif CRYPTO_LITTLE_ENDIAN
219  count *= sizeof(limb_t);
220  if (len <= count) {
221  memcpy(bytes, limbs, len);
222  } else {
223  memcpy(bytes, limbs, count);
224  memset(bytes + count, 0, len - count);
225  }
226 #elif BIGNUMBER_LIMB_16BIT
227  limb_t word;
228  while (count > 0 && len >= 2) {
229  word = *limbs++;
230  bytes[0] = (uint8_t)word;
231  bytes[1] = (uint8_t)(word >> 8);
232  --count;
233  len -= 2;
234  bytes += 2;
235  }
236  if (count > 0 && len == 1) {
237  bytes[0] = (uint8_t)(*limbs);
238  --len;
239  ++bytes;
240  }
241  memset(bytes, 0, len);
242 #elif BIGNUMBER_LIMB_32BIT
243  limb_t word;
244  while (count > 0 && len >= 4) {
245  word = *limbs++;
246  bytes[0] = (uint8_t)word;
247  bytes[1] = (uint8_t)(word >> 8);
248  bytes[2] = (uint8_t)(word >> 16);
249  bytes[3] = (uint8_t)(word >> 24);
250  --count;
251  len -= 4;
252  bytes += 4;
253  }
254  if (count > 0) {
255  if (len == 3) {
256  word = *limbs;
257  bytes[0] = (uint8_t)word;
258  bytes[1] = (uint8_t)(word >> 8);
259  bytes[2] = (uint8_t)(word >> 16);
260  len -= 3;
261  bytes += 3;
262  } else if (len == 2) {
263  word = *limbs;
264  bytes[0] = (uint8_t)word;
265  bytes[1] = (uint8_t)(word >> 8);
266  len -= 2;
267  bytes += 2;
268  } else if (len == 1) {
269  bytes[0] = (uint8_t)(*limbs);
270  --len;
271  ++bytes;
272  }
273  }
274  memset(bytes, 0, len);
275 #endif
276 }
277 
294 void BigNumberUtil::packBE(uint8_t *bytes, size_t len,
295  const limb_t *limbs, size_t count)
296 {
297 #if BIGNUMBER_LIMB_8BIT
298  if (len > count) {
299  size_t size = len - count;
300  memset(bytes, 0, size);
301  len -= size;
302  bytes += size;
303  } else if (len < count) {
304  count = len;
305  }
306  limbs += count;
307  while (count > 0) {
308  --count;
309  *bytes++ = *(--limbs);
310  }
311 #elif BIGNUMBER_LIMB_16BIT
312  size_t countBytes = count * sizeof(limb_t);
313  limb_t word;
314  if (len >= countBytes) {
315  size_t size = len - countBytes;
316  memset(bytes, 0, size);
317  len -= size;
318  bytes += size;
319  limbs += count;
320  } else {
321  count = len / sizeof(limb_t);
322  limbs += count;
323  if ((len & 1) != 0)
324  *bytes++ = (uint8_t)(*limbs);
325  }
326  while (count > 0) {
327  --count;
328  word = *(--limbs);
329  *bytes++ = (uint8_t)(word >> 8);
330  *bytes++ = (uint8_t)word;
331  }
332 #elif BIGNUMBER_LIMB_32BIT
333  size_t countBytes = count * sizeof(limb_t);
334  limb_t word;
335  if (len >= countBytes) {
336  size_t size = len - countBytes;
337  memset(bytes, 0, size);
338  len -= size;
339  bytes += size;
340  limbs += count;
341  } else {
342  count = len / sizeof(limb_t);
343  limbs += count;
344  if ((len & 3) == 3) {
345  word = *limbs;
346  *bytes++ = (uint8_t)(word >> 16);
347  *bytes++ = (uint8_t)(word >> 8);
348  *bytes++ = (uint8_t)word;
349  } else if ((len & 3) == 2) {
350  word = *limbs;
351  *bytes++ = (uint8_t)(word >> 8);
352  *bytes++ = (uint8_t)word;
353  } else if ((len & 3) == 1) {
354  *bytes++ = (uint8_t)(*limbs);
355  }
356  }
357  while (count > 0) {
358  --count;
359  word = *(--limbs);
360  *bytes++ = (uint8_t)(word >> 24);
361  *bytes++ = (uint8_t)(word >> 16);
362  *bytes++ = (uint8_t)(word >> 8);
363  *bytes++ = (uint8_t)word;
364  }
365 #endif
366 }
367 
381 limb_t BigNumberUtil::add(limb_t *result, const limb_t *x,
382  const limb_t *y, size_t size)
383 {
384  dlimb_t carry = 0;
385  while (size > 0) {
386  carry += *x++;
387  carry += *y++;
388  *result++ = (limb_t)carry;
389  carry >>= LIMB_BITS;
390  --size;
391  }
392  return (limb_t)carry;
393 }
394 
408 limb_t BigNumberUtil::sub(limb_t *result, const limb_t *x,
409  const limb_t *y, size_t size)
410 {
411  dlimb_t borrow = 0;
412  while (size > 0) {
413  borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
414  *result++ = (limb_t)borrow;
415  --size;
416  }
417  return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
418 }
419 
432 void BigNumberUtil::mul(limb_t *result, const limb_t *x, size_t xcount,
433  const limb_t *y, size_t ycount)
434 {
435  size_t i, j;
436  dlimb_t carry;
437  limb_t word;
438  const limb_t *xx;
439  limb_t *rr;
440 
441  // Multiply the lowest limb of y by x.
442  carry = 0;
443  word = y[0];
444  xx = x;
445  rr = result;
446  for (i = 0; i < xcount; ++i) {
447  carry += ((dlimb_t)(*xx++)) * word;
448  *rr++ = (limb_t)carry;
449  carry >>= LIMB_BITS;
450  }
451  *rr = (limb_t)carry;
452 
453  // Multiply and add the remaining limbs of y by x.
454  for (i = 1; i < ycount; ++i) {
455  word = y[i];
456  carry = 0;
457  xx = x;
458  rr = result + i;
459  for (j = 0; j < xcount; ++j) {
460  carry += ((dlimb_t)(*xx++)) * word;
461  carry += *rr;
462  *rr++ = (limb_t)carry;
463  carry >>= LIMB_BITS;
464  }
465  *rr = (limb_t)carry;
466  }
467 }
468 
484 void BigNumberUtil::reduceQuick(limb_t *result, const limb_t *x,
485  const limb_t *y, size_t size)
486 {
487  // Subtract "y" from "x" and turn the borrow into an AND mask.
488  limb_t mask = sub(result, x, y, size);
489  mask = (~mask) + 1;
490 
491  // Add "y" back to the result if the mask is non-zero.
492  dlimb_t carry = 0;
493  while (size > 0) {
494  carry += *result;
495  carry += (*y++ & mask);
496  *result++ = (limb_t)carry;
497  carry >>= LIMB_BITS;
498  --size;
499  }
500 }
501 
514 limb_t BigNumberUtil::add_P(limb_t *result, const limb_t *x,
515  const limb_t *y, size_t size)
516 {
517  dlimb_t carry = 0;
518  while (size > 0) {
519  carry += *x++;
520  carry += pgm_read_limb(y++);
521  *result++ = (limb_t)carry;
522  carry >>= LIMB_BITS;
523  --size;
524  }
525  return (limb_t)carry;
526 }
527 
541 limb_t BigNumberUtil::sub_P(limb_t *result, const limb_t *x,
542  const limb_t *y, size_t size)
543 {
544  dlimb_t borrow = 0;
545  while (size > 0) {
546  borrow = ((dlimb_t)(*x++)) - pgm_read_limb(y++) - ((borrow >> LIMB_BITS) & 0x01);
547  *result++ = (limb_t)borrow;
548  --size;
549  }
550  return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
551 }
552 
566 void BigNumberUtil::mul_P(limb_t *result, const limb_t *x, size_t xcount,
567  const limb_t *y, size_t ycount)
568 {
569  size_t i, j;
570  dlimb_t carry;
571  limb_t word;
572  const limb_t *xx;
573  limb_t *rr;
574 
575  // Multiply the lowest limb of y by x.
576  carry = 0;
577  word = pgm_read_limb(&(y[0]));
578  xx = x;
579  rr = result;
580  for (i = 0; i < xcount; ++i) {
581  carry += ((dlimb_t)(*xx++)) * word;
582  *rr++ = (limb_t)carry;
583  carry >>= LIMB_BITS;
584  }
585  *rr = (limb_t)carry;
586 
587  // Multiply and add the remaining limb of y by x.
588  for (i = 1; i < ycount; ++i) {
589  word = pgm_read_limb(&(y[i]));
590  carry = 0;
591  xx = x;
592  rr = result + i;
593  for (j = 0; j < xcount; ++j) {
594  carry += ((dlimb_t)(*xx++)) * word;
595  carry += *rr;
596  *rr++ = (limb_t)carry;
597  carry >>= LIMB_BITS;
598  }
599  *rr = (limb_t)carry;
600  }
601 }
602 
620 void BigNumberUtil::reduceQuick_P(limb_t *result, const limb_t *x,
621  const limb_t *y, size_t size)
622 {
623  // Subtract "y" from "x" and turn the borrow into an AND mask.
624  limb_t mask = sub_P(result, x, y, size);
625  mask = (~mask) + 1;
626 
627  // Add "y" back to the result if the mask is non-zero.
628  dlimb_t carry = 0;
629  while (size > 0) {
630  carry += *result;
631  carry += (pgm_read_limb(y++) & mask);
632  *result++ = (limb_t)carry;
633  carry >>= LIMB_BITS;
634  --size;
635  }
636 }
static void reduceQuick_P(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Reduces x modulo y using subtraction where y is in program memory.
static limb_t add(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Adds two big numbers.
static limb_t sub_P(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Subtracts one big number from another where one is in program memory.
static void reduceQuick(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Reduces x modulo y using subtraction.
static limb_t sub(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Subtracts one big number from another.
static void mul_P(limb_t *result, const limb_t *x, size_t xcount, const limb_t *y, size_t ycount)
Multiplies two big numbers where one is in program memory.
static void packBE(uint8_t *bytes, size_t len, const limb_t *limbs, size_t count)
Packs the big-endian byte representation of a big number into a byte array.
static void unpackLE(limb_t *limbs, size_t count, const uint8_t *bytes, size_t len)
Unpacks the little-endian byte representation of a big number into a limb array.
static void mul(limb_t *result, const limb_t *x, size_t xcount, const limb_t *y, size_t ycount)
Multiplies two big numbers.
static void unpackBE(limb_t *limbs, size_t count, const uint8_t *bytes, size_t len)
Unpacks the big-endian byte representation of a big number into a limb array.
static void packLE(uint8_t *bytes, size_t len, const limb_t *limbs, size_t count)
Packs the little-endian byte representation of a big number into a byte array.
static limb_t add_P(limb_t *result, const limb_t *x, const limb_t *y, size_t size)
Adds two big numbers where one of them is in program memory.