Skip to content

Commit 8419431

Browse files
isojalkahifi
authored andcommitted
Endian fixes for the multiprecision code.
The code mostly uses multiprecision integers built up from arrays of 32 bit integers, but will in some cases interchangably treat said arrays as having 16 bit components instead, expecting to read the least significant bytes at lower address and most significant bytes at higher addresses. This change introduces two helper functions to emulate this behaviour - Get_HalfWord() and Set_HalfWord() - which are used instead of directly accessing the 32 bit integer arrays with 16 bit pointers. XMP_Encode() also got endian fixes that are unrelated to the above.
1 parent ac7f03e commit 8419431

2 files changed

Lines changed: 133 additions & 32 deletions

File tree

common/mp.cpp

Lines changed: 132 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,33 @@
8787
#include <algorithm>
8888
#include "mp.h"
8989
#include "memrev.h"
90+
#include "endianness.h"
91+
92+
#ifdef __BIG_ENDIAN__
93+
#define HALFWORD_0 1
94+
#define HALFWORD_1 0
95+
#else
96+
#define HALFWORD_0 0
97+
#define HALFWORD_1 1
98+
#endif
99+
100+
static inline uint16_t Get_HalfWord(const uint16_t* base, size_t offset)
101+
{
102+
#ifdef __BIG_ENDIAN__
103+
return base[offset ^ 1];
104+
#else
105+
return base[offset];
106+
#endif
107+
}
108+
109+
static inline void Set_HalfWord(uint16_t* base, size_t offset, uint16_t value)
110+
{
111+
#ifdef __BIG_ENDIAN__
112+
base[offset ^ 1] = value;
113+
#else
114+
base[offset] = value;
115+
#endif
116+
}
90117

91118
/***********************************************************************************************
92119
* _Byte_Precision -- Determines the number of bytes significant in long integer. *
@@ -306,11 +333,27 @@ unsigned XMP_Encode(unsigned char* to, unsigned tobytes, digit const* from, int
306333
//#pragma warning 364 9
307334
unsigned XMP_Encode(unsigned char* to, digit const* from, int precision)
308335
{
336+
int i;
337+
#ifdef __BIG_ENDIAN__
338+
digit from_copy[precision];
339+
#endif
340+
309341
assert(to != NULL);
310342
assert(from != NULL);
311343
assert(precision > 0);
312344

313345
bool is_negative = XMP_Is_Negative(from, precision);
346+
347+
#ifdef __BIG_ENDIAN__
348+
if (sizeof(digit) == 4) {
349+
for (i = 0; i < precision; i++) {
350+
from_copy[i] = le32toh(from[i]);
351+
}
352+
}
353+
354+
from = from_copy;
355+
#endif
356+
314357
unsigned char filler = (unsigned char)(is_negative ? 0xff : 0);
315358
unsigned char* number_ptr;
316359

@@ -381,6 +424,12 @@ void XMP_Signed_Decode(digit* result, const unsigned char* from, int frombytes,
381424
for (index = 0; index < frombytes; index++) {
382425
*--dest = *from++;
383426
}
427+
428+
if (sizeof(digit) == 4) {
429+
for (index = 0; index < precision; index++) {
430+
result[index] = le32toh(result[index]);
431+
}
432+
}
384433
}
385434

386435
/***********************************************************************************************
@@ -1068,18 +1117,58 @@ bool XMP_Add_Int(digit* result, const digit* left_number, digit right_number, bo
10681117
* HISTORY: *
10691118
* 07/01/1996 JLB : Created. *
10701119
*=============================================================================================*/
1120+
bool XMP_Sub(uint16_t* result,
1121+
size_t result_offset,
1122+
const uint16_t* left_number,
1123+
size_t left_number_offset,
1124+
const digit* right_number,
1125+
bool borrow,
1126+
int precision)
1127+
{
1128+
bool ret;
1129+
1130+
#ifdef __BIG_ENDIAN__
1131+
uint16_t temp_left_number[precision * 2];
1132+
uint16_t temp_result[precision * 2];
1133+
size_t i;
1134+
1135+
for (i = 0; i < precision * 2; i++) {
1136+
Set_HalfWord(temp_left_number, i, Get_HalfWord(left_number, left_number_offset + i));
1137+
}
1138+
1139+
ret = XMP_Sub((digit*)temp_result, (const digit*)temp_left_number, right_number, borrow, precision);
1140+
1141+
for (i = 0; i < precision * 2; i++) {
1142+
Set_HalfWord(result, result_offset + i, Get_HalfWord(temp_result, i));
1143+
}
1144+
#else
1145+
ret = XMP_Sub((digit*)(result + result_offset),
1146+
(const digit*)(left_number + left_number_offset),
1147+
right_number,
1148+
borrow,
1149+
precision);
1150+
#endif
1151+
1152+
return ret;
1153+
}
1154+
10711155
bool XMP_Sub(digit* result, const digit* left_number, const digit* right_number, bool borrow, int precision)
10721156
{
10731157
const uint16_t* left_number_ptr = (const uint16_t*)left_number;
1158+
size_t left_number_offset = 0;
10741159
const uint16_t* right_number_ptr = (const uint16_t*)right_number;
1160+
size_t right_number_offset = 0;
10751161
uint16_t* result_ptr = (uint16_t*)result;
1162+
size_t result_offset = 0;
10761163

10771164
precision *= 2;
10781165
while (precision--) {
1079-
digit x = (digit)*left_number_ptr - (digit)*right_number_ptr - (digit)borrow;
1080-
right_number_ptr++;
1081-
left_number_ptr++;
1082-
*result_ptr++ = (uint16_t)x;
1166+
digit x = (digit)Get_HalfWord(left_number_ptr, left_number_offset)
1167+
- (digit)Get_HalfWord(right_number_ptr, right_number_offset) - (digit)borrow;
1168+
right_number_offset++;
1169+
left_number_offset++;
1170+
Set_HalfWord(result_ptr, result_offset, x);
1171+
result_offset++;
10831172
borrow = (((1L << 16) & x) != 0L);
10841173
}
10851174
return (borrow);
@@ -1748,18 +1837,23 @@ void XMP_Decode_ASCII(char const* str, digit* mpn, int precision)
17481837
* HISTORY: *
17491838
* 07/02/1996 JLB : Created. *
17501839
*=============================================================================================*/
1751-
void XMP_Hybrid_Mul(uint16_t* prod, uint16_t* multiplicand, uint16_t multiplier, int precision)
1840+
void XMP_Hybrid_Mul(uint16_t* prod,
1841+
size_t prod_offset,
1842+
uint16_t* multiplicand,
1843+
size_t multiplicand_offset,
1844+
uint16_t multiplier,
1845+
int precision)
17521846
{
17531847
uint32_t carry = 0;
17541848
for (int i = 0; i < precision; ++i) {
1755-
uint32_t p = (uint32_t)multiplier * *multiplicand++;
1756-
p += *prod + carry;
1757-
*prod++ = (uint16_t)p;
1849+
uint32_t p = (uint32_t)multiplier * Get_HalfWord(multiplicand, multiplicand_offset++);
1850+
p += Get_HalfWord(prod, prod_offset) + carry;
1851+
Set_HalfWord(prod, prod_offset++, (uint16_t)p);
17581852
carry = p >> 16;
17591853
}
17601854

17611855
/* Add carry to the next higher word of product / dividend */
1762-
*prod += (uint16_t)carry;
1856+
Set_HalfWord(prod, prod_offset, Get_HalfWord(prod, prod_offset) + (uint16_t)carry);
17631857
}
17641858

17651859
/***********************************************************************************************
@@ -1791,12 +1885,17 @@ void XMP_Double_Mul(digit* prod, const digit* multiplicand, const digit* multipl
17911885
*/
17921886
XMP_Init(prod, 0, precision * 2);
17931887

1794-
const uint16_t* multiplier_ptr = (const uint16_t*)multiplier;
1795-
uint16_t* product_ptr = (uint16_t*)prod;
1888+
size_t multiplier_offset = 0;
1889+
size_t product_offset = 0;
17961890

17971891
// Multiply multiplicand by each word in multiplier, accumulating prod.
17981892
for (int i = 0; i < precision * 2; ++i) {
1799-
XMP_Hybrid_Mul(product_ptr++, (uint16_t*)multiplicand, *multiplier_ptr++, precision * 2);
1893+
XMP_Hybrid_Mul((uint16_t*)prod,
1894+
product_offset++,
1895+
(uint16_t*)multiplicand,
1896+
0,
1897+
Get_HalfWord((const uint16_t*)multiplier, multiplier_offset++),
1898+
precision * 2);
18001899
}
18011900
}
18021901

@@ -1867,8 +1966,8 @@ int XMP_Prepare_Modulus(const digit* n_modulus, int precision)
18671966
_modulus_shift--; /* now 0 <= _modulus_shift <= 16 */
18681967
}
18691968
uint16_t* mpm = (uint16_t*)_mod_quotient;
1870-
_reciprical_low_digit = *mpm++;
1871-
_reciprical_high_digit = *mpm;
1969+
_reciprical_low_digit = Get_HalfWord(mpm, 0);
1970+
_reciprical_high_digit = Get_HalfWord(mpm, 1);
18721971

18731972
return 0;
18741973
}
@@ -1928,9 +2027,10 @@ int XMP_Mod_Mult(digit* prod, const digit* multiplicand, const digit* multiplier
19282027
int nqd = dmi + 1 - _modulus_sub_precision; // number of quotient digits remaining to be generated
19292028

19302029
/* Set msb, lsb, and normal ptrs of dividend */
1931-
uint16_t* dmph =
1932-
((uint16_t*)_double_staging_number) + dmi + 1; // points to one higher than precision would indicate
1933-
uint16_t* dmpl = dmph - _modulus_sub_precision;
2030+
size_t dmph_offset = dmi + 1;
2031+
uint16_t* dmph = (uint16_t*)_double_staging_number;
2032+
size_t dmpl_offset = dmph_offset - _modulus_sub_precision;
2033+
uint16_t* dmpl = dmph;
19342034

19352035
/*
19362036
** Divide loop.
@@ -1942,20 +2042,19 @@ int XMP_Mod_Mult(digit* prod, const digit* multiplicand, const digit* multiplier
19422042
** modulus to get the proper negative remainder.
19432043
*/
19442044
for (; nqd; nqd--) {
1945-
--dmph;
1946-
--dmpl;
2045+
--dmph_offset;
2046+
--dmpl_offset;
19472047

1948-
uint16_t q = mp_quo_digit(dmph); // trial quotient digit
2048+
uint16_t q = mp_quo_digit(dmph, dmph_offset); // trial quotient digit
19492049
if (q > 0) {
1950-
XMP_Hybrid_Mul(dmpl, (uint16_t*)_scratch_modulus, q, precision * 2);
2050+
XMP_Hybrid_Mul(dmpl, dmpl_offset, (uint16_t*)_scratch_modulus, 0, q, precision * 2);
19512051

19522052
/* Perform correction if q too large.
19532053
** This rarely occurs.
19542054
*/
1955-
if (!(*dmph & SEMI_UPPER_MOST_BIT)) {
1956-
uint16_t* dmp = dmpl;
1957-
if (XMP_Sub((uint32_t*)dmp, (uint32_t*)dmp, _scratch_modulus, false, precision)) {
1958-
(*dmph)--;
2055+
if (!(Get_HalfWord(dmph, dmph_offset) & SEMI_UPPER_MOST_BIT)) {
2056+
if (XMP_Sub(dmpl, dmpl_offset, dmpl, dmpl_offset, _scratch_modulus, false, precision)) {
2057+
Set_HalfWord(dmph, dmph_offset, Get_HalfWord(dmph, dmph_offset) - 1);
19592058
}
19602059
}
19612060
}
@@ -2024,7 +2123,7 @@ void XMP_Mod_Mult_Clear(int precision)
20242123
** three MULTUNITs at dividend by the upper two MULTUNITs of the
20252124
** modulus.
20262125
*/
2027-
uint16_t mp_quo_digit(uint16_t* dividend)
2126+
uint16_t mp_quo_digit(uint16_t* dividend, size_t dividend_offset)
20282127
{
20292128
uint32_t q, q0, q1, q2;
20302129

@@ -2033,17 +2132,19 @@ uint16_t mp_quo_digit(uint16_t* dividend)
20332132
* The last terms of q1 and q2 perform upward rounding, which is
20342133
* needed to guarantee that the result not be too small.
20352134
*/
2036-
q1 = (dividend[-2] ^ SEMI_MASK) * (uint32_t)_reciprical_high_digit + _reciprical_high_digit;
2037-
q2 = (dividend[-1] ^ SEMI_MASK) * (uint32_t)_reciprical_low_digit + (1L << 16);
2135+
q1 = (Get_HalfWord(dividend, dividend_offset - 2) ^ SEMI_MASK) * (uint32_t)_reciprical_high_digit
2136+
+ _reciprical_high_digit;
2137+
q2 = (Get_HalfWord(dividend, dividend_offset - 1) ^ SEMI_MASK) * (uint32_t)_reciprical_low_digit + (1L << 16);
20382138
q0 = (q1 >> 1) + (q2 >> 1) + 1;
20392139

20402140
/* Compute the middle significant product group. */
2041-
q1 = (dividend[-1] ^ SEMI_MASK) * (uint32_t)_reciprical_high_digit;
2042-
q2 = (dividend[0] ^ SEMI_MASK) * (uint32_t)_reciprical_low_digit;
2141+
q1 = (Get_HalfWord(dividend, dividend_offset - 1) ^ SEMI_MASK) * (uint32_t)_reciprical_high_digit;
2142+
q2 = (Get_HalfWord(dividend, dividend_offset) ^ SEMI_MASK) * (uint32_t)_reciprical_low_digit;
20432143
q = (q0 >> 16) + (q1 >> 1) + (q2 >> 1) + 1;
20442144

20452145
/* Compute the most significant term and add in the others */
2046-
q = (q >> (16 - 2)) + (((dividend[0] ^ SEMI_MASK) * (uint32_t)_reciprical_high_digit) << 1);
2146+
q = (q >> (16 - 2))
2147+
+ (((Get_HalfWord(dividend, dividend_offset) ^ SEMI_MASK) * (uint32_t)_reciprical_high_digit) << 1);
20472148
q >>= _modulus_shift;
20482149

20492150
/* Prevent overflow and then wipe out the intermediate results. */

common/mp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void XMP_Double_Mul(digit* prod, const digit* multiplicand, const digit* multipl
8484
int xmp_stage_modulus(const digit* n_modulus, int precision);
8585
int XMP_Mod_Mult(digit* prod, const digit* multiplicand, const digit* multiplier, int precision);
8686
void XMP_Mod_Mult_Clear(int precision);
87-
uint16_t mp_quo_digit(uint16_t* dividend);
87+
uint16_t mp_quo_digit(uint16_t* dividend, size_t dividend_offset);
8888
int xmp_exponent_mod(digit* expout, const digit* expin, const digit* exponent_ptr, const digit* modulus, int precision);
8989
bool XMP_Is_Small_Prime(const digit* candidate, int precision);
9090
bool XMP_Small_Divisors_Test(const digit* candidate, int precision);

0 commit comments

Comments
 (0)