| /* | |
| * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of the | |
| * License, or any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, but | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| * 02110-1301, USA. | |
| * | |
| * You can also choose to distribute this program under the terms of | |
| * the Unmodified Binary Distribution Licence (as given in the file | |
| * COPYING.UBDL), provided that you have satisfied its requirements. | |
| */ | |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | |
| FILE_SECBOOT ( PERMITTED ); | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include <strings.h> | |
| #include <assert.h> | |
| #include <byteswap.h> | |
| #include <stdio.h> | |
| #include <ipxe/bigint.h> | |
| /** @file | |
| * | |
| * Big integer support | |
| */ | |
| /** Minimum number of least significant bytes included in transcription */ | |
| #define BIGINT_NTOA_LSB_MIN 16 | |
| /** | |
| * Transcribe big integer (for debugging) | |
| * | |
| * @v value0 Element 0 of big integer to be transcribed | |
| * @v size Number of elements | |
| * @ret string Big integer in string form (may be abbreviated) | |
| */ | |
| const char * bigint_ntoa_raw ( const bigint_element_t *value0, | |
| unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *value = ( ( const void * ) value0 ); | |
| bigint_element_t element; | |
| static char buf[256]; | |
| unsigned int count; | |
| int threshold; | |
| uint8_t byte; | |
| char *tmp; | |
| int i; | |
| /* Calculate abbreviation threshold, if any */ | |
| count = ( size * sizeof ( element ) ); | |
| threshold = count; | |
| if ( count >= ( ( sizeof ( buf ) - 1 /* NUL */ ) / 2 /* "xx" */ ) ) { | |
| threshold -= ( ( sizeof ( buf ) - 3 /* "..." */ | |
| - ( BIGINT_NTOA_LSB_MIN * 2 /* "xx" */ ) | |
| - 1 /* NUL */ ) / 2 /* "xx" */ ); | |
| } | |
| /* Transcribe bytes, abbreviating with "..." if necessary */ | |
| for ( tmp = buf, i = ( count - 1 ) ; i >= 0 ; i-- ) { | |
| element = value->element[ i / sizeof ( element ) ]; | |
| byte = ( element >> ( 8 * ( i % sizeof ( element ) ) ) ); | |
| tmp += sprintf ( tmp, "%02x", byte ); | |
| if ( i == threshold ) { | |
| tmp += sprintf ( tmp, "..." ); | |
| i = BIGINT_NTOA_LSB_MIN; | |
| } | |
| } | |
| assert ( tmp < ( buf + sizeof ( buf ) ) ); | |
| return buf; | |
| } | |
| /** | |
| * Initialise big integer | |
| * | |
| * @v value0 Element 0 of big integer to initialise | |
| * @v size Number of elements | |
| * @v data Raw data | |
| * @v len Length of raw data | |
| */ | |
| void bigint_init_raw ( bigint_element_t *value0, unsigned int size, | |
| const void *data, size_t len ) { | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *value = ( ( void * ) value0 ); | |
| uint8_t *value_byte = ( ( void * ) value0 ); | |
| const uint8_t *data_byte = data; | |
| unsigned int toggle; | |
| unsigned int i; | |
| /* Zero big integer */ | |
| memset ( value, 0, sizeof ( *value ) ); | |
| /* Copy data, byte-swapping as needed */ | |
| toggle = ( ( __BYTE_ORDER == __LITTLE_ENDIAN ) ? 0 : | |
| ( sizeof ( value->element[0] ) - 1 ) ); | |
| for ( i = 0 ; len-- ; i++ ) | |
| value_byte[ i ^ toggle ] = data_byte[len]; | |
| } | |
| /** | |
| * Finalise big integer | |
| * | |
| * @v value0 Element 0 of big integer to finalise | |
| * @v size Number of elements | |
| * @v out Output buffer | |
| * @v len Length of output buffer | |
| */ | |
| void bigint_done_raw ( const bigint_element_t *value0, unsigned int size, | |
| void *out, size_t len ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *value = ( ( const void * ) value0 ); | |
| const uint8_t *value_byte = ( ( const void * ) value0 ); | |
| uint8_t *out_byte = out; | |
| unsigned int toggle; | |
| unsigned int i; | |
| /* Zero output buffer */ | |
| memset ( out, 0, len ); | |
| /* Copy data, byte-swapping as needed */ | |
| toggle = ( ( __BYTE_ORDER == __LITTLE_ENDIAN ) ? 0 : | |
| ( sizeof ( value->element[0] ) - 1 ) ); | |
| for ( i = 0 ; len-- ; i++ ) | |
| out_byte[len] = value_byte[ i ^ toggle ]; | |
| } | |
| /** | |
| * Test if big integer is equal to zero | |
| * | |
| * @v value0 Element 0 of big integer | |
| * @v size Number of elements | |
| * @ret is_zero Big integer is equal to zero | |
| */ | |
| int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( const void * ) value0 ); | |
| bigint_element_t or; | |
| unsigned int i; | |
| /* Construct binary OR of all elements */ | |
| for ( i = 0, or = 0 ; i < size ; i++ ) | |
| or |= value->element[i]; | |
| return ( or == 0 ); | |
| } | |
| /** | |
| * Compare big integers | |
| * | |
| * @v value0 Element 0 of big integer | |
| * @v reference0 Element 0 of reference big integer | |
| * @v size Number of elements | |
| * @ret geq Big integer is greater than or equal to the reference | |
| */ | |
| int bigint_is_geq_raw ( const bigint_element_t *value0, | |
| const bigint_element_t *reference0, | |
| unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( const void * ) value0 ); | |
| const bigint_t ( size ) __attribute__ (( may_alias )) *reference = | |
| ( ( const void * ) reference0 ); | |
| bigint_element_t value_element; | |
| bigint_element_t reference_element; | |
| /* Find highest differing element */ | |
| do { | |
| value_element = value->element[ size - 1 ]; | |
| reference_element = reference->element[ size - 1 ]; | |
| if ( value_element != reference_element ) | |
| break; | |
| } while ( --size ); | |
| return ( value_element >= reference_element ); | |
| } | |
| /** | |
| * Find highest bit set in big integer | |
| * | |
| * @v value0 Element 0 of big integer | |
| * @v size Number of elements | |
| * @ret max_bit Highest bit set + 1 (or 0 if no bits set) | |
| */ | |
| int bigint_max_set_bit_raw ( const bigint_element_t *value0, | |
| unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) *value = | |
| ( ( const void * ) value0 ); | |
| bigint_element_t element; | |
| unsigned int max_bit; | |
| unsigned int i; | |
| /* Find highest set bit in highest non-zero element */ | |
| max_bit = ( sizeof ( *value ) * 8 ); | |
| for ( i = 0 ; i < size ; i++ ) { | |
| element = value->element[ size - i - 1 ]; | |
| max_bit -= ( sizeof ( element) * 8 ); | |
| if ( element ) { | |
| max_bit += flsll ( element ); | |
| break; | |
| } | |
| } | |
| return max_bit; | |
| } | |
| /** | |
| * Conditionally swap big integers (in constant time) | |
| * | |
| * @v first0 Element 0 of big integer to be conditionally swapped | |
| * @v second0 Element 0 of big integer to be conditionally swapped | |
| * @v size Number of elements in big integers | |
| * @v swap Swap first and second big integers | |
| */ | |
| void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0, | |
| unsigned int size, int swap ) { | |
| bigint_element_t mask; | |
| bigint_element_t xor; | |
| unsigned int i; | |
| /* Construct mask */ | |
| mask = ( ( bigint_element_t ) ( ! swap ) - 1 ); | |
| /* Conditionally swap elements */ | |
| for ( i = 0 ; i < size ; i++ ) { | |
| xor = ( mask & ( first0[i] ^ second0[i] ) ); | |
| first0[i] ^= xor; | |
| second0[i] ^= xor; | |
| } | |
| } | |
| /** | |
| * Multiply big integers | |
| * | |
| * @v multiplicand0 Element 0 of big integer to be multiplied | |
| * @v multiplicand_size Number of elements in multiplicand | |
| * @v multiplier0 Element 0 of big integer to be multiplied | |
| * @v multiplier_size Number of elements in multiplier | |
| * @v result0 Element 0 of big integer to hold result | |
| */ | |
| void bigint_multiply_raw ( const bigint_element_t *multiplicand0, | |
| unsigned int multiplicand_size, | |
| const bigint_element_t *multiplier0, | |
| unsigned int multiplier_size, | |
| bigint_element_t *result0 ) { | |
| unsigned int result_size = ( multiplicand_size + multiplier_size ); | |
| const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) | |
| *multiplicand = ( ( const void * ) multiplicand0 ); | |
| const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) | |
| *multiplier = ( ( const void * ) multiplier0 ); | |
| bigint_t ( result_size ) __attribute__ (( may_alias )) | |
| *result = ( ( void * ) result0 ); | |
| bigint_element_t multiplicand_element; | |
| const bigint_element_t *multiplier_element; | |
| bigint_element_t *result_element; | |
| bigint_element_t carry_element; | |
| unsigned int i; | |
| unsigned int j; | |
| /* Zero required portion of result | |
| * | |
| * All elements beyond the length of the multiplier will be | |
| * written before they are read, and so do not need to be | |
| * zeroed in advance. | |
| */ | |
| memset ( result, 0, sizeof ( *multiplier ) ); | |
| /* Multiply integers one element at a time, adding the low | |
| * half of the double-element product directly into the | |
| * result, and maintaining a running single-element carry. | |
| * | |
| * The running carry can never overflow beyond a single | |
| * element. At each step, the calculation we perform is: | |
| * | |
| * carry:result[i+j] := ( ( multiplicand[i] * multiplier[j] ) | |
| * + result[i+j] + carry ) | |
| * | |
| * The maximum value (for n-bit elements) is therefore: | |
| * | |
| * (2^n - 1)*(2^n - 1) + (2^n - 1) + (2^n - 1) = 2^(2n) - 1 | |
| * | |
| * This is precisely the maximum value for a 2n-bit integer, | |
| * and so the carry out remains within the range of an n-bit | |
| * integer, i.e. a single element. | |
| */ | |
| for ( i = 0 ; i < multiplicand_size ; i++ ) { | |
| multiplicand_element = multiplicand->element[i]; | |
| multiplier_element = &multiplier->element[0]; | |
| result_element = &result->element[i]; | |
| carry_element = 0; | |
| for ( j = 0 ; j < multiplier_size ; j++ ) { | |
| bigint_multiply_one ( multiplicand_element, | |
| *(multiplier_element++), | |
| result_element++, | |
| &carry_element ); | |
| } | |
| *result_element = carry_element; | |
| } | |
| } | |
| /** | |
| * Reduce big integer R^2 modulo N | |
| * | |
| * @v modulus0 Element 0 of big integer modulus | |
| * @v result0 Element 0 of big integer to hold result | |
| * @v size Number of elements in modulus and result | |
| * | |
| * Reduce the value R^2 modulo N, where R=2^n and n is the number of | |
| * bits in the representation of the modulus N, including any leading | |
| * zero bits. | |
| */ | |
| void bigint_reduce_raw ( const bigint_element_t *modulus0, | |
| bigint_element_t *result0, unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *modulus = ( ( const void * ) modulus0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *result = ( ( void * ) result0 ); | |
| const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); | |
| unsigned int shift; | |
| int max; | |
| int sign; | |
| int msb; | |
| int carry; | |
| /* We have the constants: | |
| * | |
| * N = modulus | |
| * | |
| * n = number of bits in the modulus (including any leading zeros) | |
| * | |
| * R = 2^n | |
| * | |
| * Let r be the extension of the n-bit result register by a | |
| * separate two's complement sign bit, such that -R <= r < R, | |
| * and define: | |
| * | |
| * x = r * 2^k | |
| * | |
| * as the value being reduced modulo N, where k is a | |
| * non-negative integer bit shift. | |
| * | |
| * We want to reduce the initial value R^2=2^(2n), which we | |
| * may trivially represent using r=1 and k=2n. | |
| * | |
| * We then iterate over decrementing k, maintaining the loop | |
| * invariant: | |
| * | |
| * -N <= r < N | |
| * | |
| * On each iteration we must first double r, to compensate for | |
| * having decremented k: | |
| * | |
| * k' = k - 1 | |
| * | |
| * r' = 2r | |
| * | |
| * x = r * 2^k = 2r * 2^(k-1) = r' * 2^k' | |
| * | |
| * Note that doubling the n-bit result register will create a | |
| * value of n+1 bits: this extra bit needs to be handled | |
| * separately during the calculation. | |
| * | |
| * We then subtract N (if r is currently non-negative) or add | |
| * N (if r is currently negative) to restore the loop | |
| * invariant: | |
| * | |
| * 0 <= r < N => r" = 2r - N => -N <= r" < N | |
| * -N <= r < 0 => r" = 2r + N => -N <= r" < N | |
| * | |
| * Note that since N may use all n bits, the most significant | |
| * bit of the n-bit result register is not a valid two's | |
| * complement sign bit for r: the extra sign bit therefore | |
| * also needs to be handled separately. | |
| * | |
| * Once we reach k=0, we have x=r and therefore: | |
| * | |
| * -N <= x < N | |
| * | |
| * After this last loop iteration (with k=0), we may need to | |
| * add a single multiple of N to ensure that x is positive, | |
| * i.e. lies within the range 0 <= x < N. | |
| * | |
| * Since neither the modulus nor the value R^2 are secret, we | |
| * may elide approximately half of the total number of | |
| * iterations by constructing the initial representation of | |
| * R^2 as r=2^m and k=2n-m (for some m such that 2^m < N). | |
| */ | |
| /* Initialise x=R^2 */ | |
| memset ( result, 0, sizeof ( *result ) ); | |
| max = ( bigint_max_set_bit ( modulus ) - 2 ); | |
| if ( max < 0 ) { | |
| /* Degenerate case of N=0 or N=1: return a zero result */ | |
| return; | |
| } | |
| bigint_set_bit ( result, max ); | |
| shift = ( ( 2 * size * width ) - max ); | |
| sign = 0; | |
| /* Iterate as described above */ | |
| while ( shift-- ) { | |
| /* Calculate 2r, storing extra bit separately */ | |
| msb = bigint_shl ( result ); | |
| /* Add or subtract N according to current sign */ | |
| if ( sign ) { | |
| carry = bigint_add ( modulus, result ); | |
| } else { | |
| carry = bigint_subtract ( modulus, result ); | |
| } | |
| /* Calculate new sign of result | |
| * | |
| * We know the result lies in the range -N <= r < N | |
| * and so the tuple (old sign, msb, carry) cannot ever | |
| * take the values (0, 1, 0) or (1, 0, 0). We can | |
| * therefore treat these as don't-care inputs, which | |
| * allows us to simplify the boolean expression by | |
| * ignoring the old sign completely. | |
| */ | |
| assert ( ( sign == msb ) || carry ); | |
| sign = ( msb ^ carry ); | |
| } | |
| /* Add N to make result positive if necessary */ | |
| if ( sign ) | |
| bigint_add ( modulus, result ); | |
| /* Sanity check */ | |
| assert ( ! bigint_is_geq ( result, modulus ) ); | |
| } | |
| /** | |
| * Compute inverse of odd big integer modulo any power of two | |
| * | |
| * @v invertend0 Element 0 of odd big integer to be inverted | |
| * @v inverse0 Element 0 of big integer to hold result | |
| * @v size Number of elements in invertend and result | |
| */ | |
| void bigint_mod_invert_raw ( const bigint_element_t *invertend0, | |
| bigint_element_t *inverse0, unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *invertend = ( ( const void * ) invertend0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *inverse = ( ( void * ) inverse0 ); | |
| bigint_element_t accum; | |
| bigint_element_t bit; | |
| unsigned int i; | |
| /* Sanity check */ | |
| assert ( bigint_bit_is_set ( invertend, 0 ) ); | |
| /* Initialise output */ | |
| memset ( inverse, 0xff, sizeof ( *inverse ) ); | |
| /* Compute inverse modulo 2^(width) | |
| * | |
| * This method is a lightly modified version of the pseudocode | |
| * presented in "A New Algorithm for Inversion mod p^k (Koç, | |
| * 2017)". | |
| * | |
| * Each inner loop iteration calculates one bit of the | |
| * inverse. The residue value is the two's complement | |
| * negation of the value "b" as used by Koç, to allow for | |
| * division by two using a logical right shift (since we have | |
| * no arithmetic right shift operation for big integers). | |
| * | |
| * The residue is stored in the as-yet uncalculated portion of | |
| * the inverse. The size of the residue therefore decreases | |
| * by one element for each outer loop iteration. Trivial | |
| * inspection of the algorithm shows that any higher bits | |
| * could not contribute to the eventual output value, and so | |
| * we may safely reuse storage this way. | |
| * | |
| * Due to the suffix property of inverses mod 2^k, the result | |
| * represents the least significant bits of the inverse modulo | |
| * an arbitrarily large 2^k. | |
| */ | |
| for ( i = size ; i > 0 ; i-- ) { | |
| const bigint_t ( i ) __attribute__ (( may_alias )) | |
| *addend = ( ( const void * ) invertend ); | |
| bigint_t ( i ) __attribute__ (( may_alias )) | |
| *residue = ( ( void * ) inverse ); | |
| /* Calculate one element's worth of inverse bits */ | |
| for ( accum = 0, bit = 1 ; bit ; bit <<= 1 ) { | |
| if ( bigint_bit_is_set ( residue, 0 ) ) { | |
| accum |= bit; | |
| bigint_add ( addend, residue ); | |
| } | |
| bigint_shr ( residue ); | |
| } | |
| /* Store in the element no longer required to hold residue */ | |
| inverse->element[ i - 1 ] = accum; | |
| } | |
| /* Correct order of inverse elements */ | |
| for ( i = 0 ; i < ( size / 2 ) ; i++ ) { | |
| accum = inverse->element[i]; | |
| inverse->element[i] = inverse->element[ size - 1 - i ]; | |
| inverse->element[ size - 1 - i ] = accum; | |
| } | |
| } | |
| /** | |
| * Perform relaxed Montgomery reduction (REDC) of a big integer | |
| * | |
| * @v modulus0 Element 0 of big integer odd modulus | |
| * @v value0 Element 0 of big integer to be reduced | |
| * @v result0 Element 0 of big integer to hold result | |
| * @v size Number of elements in modulus and result | |
| * @ret carry Carry out | |
| * | |
| * The value to be reduced will be made divisible by the size of the | |
| * modulus while retaining its residue class (i.e. multiples of the | |
| * modulus will be added until the low half of the value is zero). | |
| * | |
| * The result may be expressed as | |
| * | |
| * tR = x + mN | |
| * | |
| * where x is the input value, N is the modulus, R=2^n (where n is the | |
| * number of bits in the representation of the modulus, including any | |
| * leading zero bits), and m is the number of multiples of the modulus | |
| * added to make the result tR divisible by R. | |
| * | |
| * The maximum addend is mN <= (R-1)*N (and such an m can be proven to | |
| * exist since N is limited to being odd and therefore coprime to R). | |
| * | |
| * Since the result of this addition is one bit larger than the input | |
| * value, a carry out bit is also returned. The caller may be able to | |
| * prove that the carry out is always zero, in which case it may be | |
| * safely ignored. | |
| * | |
| * The upper half of the output value (i.e. t) will also be copied to | |
| * the result pointer. It is permissible for the result pointer to | |
| * overlap the lower half of the input value. | |
| * | |
| * External knowledge of constraints on the modulus and the input | |
| * value may be used to prove constraints on the result. The | |
| * constraint on the modulus may be generally expressed as | |
| * | |
| * R > kN | |
| * | |
| * for some positive integer k. The value k=1 is allowed, and simply | |
| * expresses that the modulus fits within the number of bits in its | |
| * own representation. | |
| * | |
| * For classic Montgomery reduction, we have k=1, i.e. R > N and a | |
| * separate constraint that the input value is in the range x < RN. | |
| * This gives the result constraint | |
| * | |
| * tR < RN + (R-1)N | |
| * < 2RN - N | |
| * < 2RN | |
| * t < 2N | |
| * | |
| * A single subtraction of the modulus may therefore be required to | |
| * bring it into the range t < N. | |
| * | |
| * When the input value is known to be a product of two integers A and | |
| * B, with A < aN and B < bN, we get the result constraint | |
| * | |
| * tR < abN^2 + (R-1)N | |
| * < (ab/k)RN + RN - N | |
| * < (1 + ab/k)RN | |
| * t < (1 + ab/k)N | |
| * | |
| * If we have k=a=b=1, i.e. R > N with A < N and B < N, then the | |
| * result is in the range t < 2N and may require a single subtraction | |
| * of the modulus to bring it into the range t < N so that it may be | |
| * used as an input on a subsequent iteration. | |
| * | |
| * If we have k=4 and a=b=2, i.e. R > 4N with A < 2N and B < 2N, then | |
| * the result is in the range t < 2N and may immediately be used as an | |
| * input on a subsequent iteration, without requiring a subtraction. | |
| * | |
| * Larger values of k may be used to allow for larger values of a and | |
| * b, which can be useful to elide intermediate reductions in a | |
| * calculation chain that involves additions and subtractions between | |
| * multiplications (as used in elliptic curve point addition, for | |
| * example). As a general rule: each intermediate addition or | |
| * subtraction will require k to be doubled. | |
| * | |
| * When the input value is known to be a single integer A, with A < aN | |
| * (as used when converting out of Montgomery form), we get the result | |
| * constraint | |
| * | |
| * tR < aN + (R-1)N | |
| * < RN + (a-1)N | |
| * | |
| * If we have a=1, i.e. A < N, then the constraint becomes | |
| * | |
| * tR < RN | |
| * t < N | |
| * | |
| * and so the result is immediately in the range t < N with no | |
| * subtraction of the modulus required. | |
| * | |
| * For any larger value of a, the result value t=N becomes possible. | |
| * Additional external knowledge may potentially be used to prove that | |
| * t=N cannot occur. For example: if the caller is performing modular | |
| * exponentiation with a prime modulus (or, more generally, a modulus | |
| * that is coprime to the base), then there is no way for a non-zero | |
| * base value to end up producing an exact multiple of the modulus. | |
| * If t=N cannot be disproved, then conversion out of Montgomery form | |
| * may require an additional subtraction of the modulus. | |
| */ | |
| int bigint_montgomery_relaxed_raw ( const bigint_element_t *modulus0, | |
| bigint_element_t *value0, | |
| bigint_element_t *result0, | |
| unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *modulus = ( ( const void * ) modulus0 ); | |
| union { | |
| bigint_t ( size * 2 ) full; | |
| struct { | |
| bigint_t ( size ) low; | |
| bigint_t ( size ) high; | |
| } __attribute__ (( packed )); | |
| } __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *result = ( ( void * ) result0 ); | |
| static bigint_t ( 1 ) cached; | |
| static bigint_t ( 1 ) negmodinv; | |
| bigint_element_t multiple; | |
| bigint_element_t carry; | |
| unsigned int i; | |
| unsigned int j; | |
| int overflow; | |
| /* Sanity checks */ | |
| assert ( bigint_bit_is_set ( modulus, 0 ) ); | |
| /* Calculate inverse (or use cached version) */ | |
| if ( cached.element[0] != modulus->element[0] ) { | |
| bigint_mod_invert ( modulus, &negmodinv ); | |
| negmodinv.element[0] = -negmodinv.element[0]; | |
| cached.element[0] = modulus->element[0]; | |
| } | |
| /* Perform multiprecision Montgomery reduction */ | |
| for ( i = 0 ; i < size ; i++ ) { | |
| /* Determine scalar multiple for this round */ | |
| multiple = ( value->low.element[i] * negmodinv.element[0] ); | |
| /* Multiply value to make it divisible by 2^(width*i) */ | |
| carry = 0; | |
| for ( j = 0 ; j < size ; j++ ) { | |
| bigint_multiply_one ( multiple, modulus->element[j], | |
| &value->full.element[ i + j ], | |
| &carry ); | |
| } | |
| /* Since value is now divisible by 2^(width*i), we | |
| * know that the current low element must have been | |
| * zeroed. | |
| */ | |
| assert ( value->low.element[i] == 0 ); | |
| /* Store the multiplication carry out in the result, | |
| * avoiding the need to immediately propagate the | |
| * carry through the remaining elements. | |
| */ | |
| result->element[i] = carry; | |
| } | |
| /* Add the accumulated carries */ | |
| overflow = bigint_add ( result, &value->high ); | |
| /* Copy to result buffer */ | |
| bigint_copy ( &value->high, result ); | |
| return overflow; | |
| } | |
| /** | |
| * Perform classic Montgomery reduction (REDC) of a big integer | |
| * | |
| * @v modulus0 Element 0 of big integer odd modulus | |
| * @v value0 Element 0 of big integer to be reduced | |
| * @v result0 Element 0 of big integer to hold result | |
| * @v size Number of elements in modulus and result | |
| */ | |
| void bigint_montgomery_raw ( const bigint_element_t *modulus0, | |
| bigint_element_t *value0, | |
| bigint_element_t *result0, | |
| unsigned int size ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *modulus = ( ( const void * ) modulus0 ); | |
| union { | |
| bigint_t ( size * 2 ) full; | |
| struct { | |
| bigint_t ( size ) low; | |
| bigint_t ( size ) high; | |
| } __attribute__ (( packed )); | |
| } __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *result = ( ( void * ) result0 ); | |
| int overflow; | |
| int underflow; | |
| /* Sanity check */ | |
| assert ( ! bigint_is_geq ( &value->high, modulus ) ); | |
| /* Perform relaxed Montgomery reduction */ | |
| overflow = bigint_montgomery_relaxed ( modulus, &value->full, result ); | |
| /* Conditionally subtract the modulus once */ | |
| underflow = bigint_subtract ( modulus, result ); | |
| bigint_swap ( result, &value->high, ( underflow & ~overflow ) ); | |
| /* Sanity check */ | |
| assert ( ! bigint_is_geq ( result, modulus ) ); | |
| } | |
| /** | |
| * Perform generalised exponentiation via a Montgomery ladder | |
| * | |
| * @v result0 Element 0 of result (initialised to identity element) | |
| * @v multiple0 Element 0 of multiple (initialised to generator) | |
| * @v size Number of elements in result and multiple | |
| * @v exponent0 Element 0 of exponent | |
| * @v exponent_size Number of elements in exponent | |
| * @v op Montgomery ladder commutative operation | |
| * @v ctx Operation context (if needed) | |
| * @v tmp Temporary working space (if needed) | |
| * | |
| * The Montgomery ladder may be used to perform any operation that is | |
| * isomorphic to exponentiation, i.e. to compute the result | |
| * | |
| * r = g^e = g * g * g * g * .... * g | |
| * | |
| * for an arbitrary commutative operation "*", generator "g" and | |
| * exponent "e". | |
| * | |
| * The result "r" is computed in constant time (assuming that the | |
| * underlying operation is constant time) in k steps, where k is the | |
| * number of bits in the big integer representation of the exponent. | |
| * | |
| * The result "r" must be initialised to the operation's identity | |
| * element, and the multiple must be initialised to the generator "g". | |
| * On exit, the multiple will contain | |
| * | |
| * m = r * g = g^(e+1) | |
| * | |
| * Note that the terminology used here refers to exponentiation | |
| * defined as repeated multiplication, but that the ladder may equally | |
| * well be used to perform any isomorphic operation (such as | |
| * multiplication defined as repeated addition). | |
| */ | |
| void bigint_ladder_raw ( bigint_element_t *result0, | |
| bigint_element_t *multiple0, unsigned int size, | |
| const bigint_element_t *exponent0, | |
| unsigned int exponent_size, bigint_ladder_op_t *op, | |
| const void *ctx, void *tmp ) { | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *result = ( ( void * ) result0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *multiple = ( ( void * ) multiple0 ); | |
| const bigint_t ( exponent_size ) __attribute__ (( may_alias )) | |
| *exponent = ( ( const void * ) exponent0 ); | |
| const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); | |
| unsigned int bit = ( exponent_size * width ); | |
| int toggle = 0; | |
| int previous; | |
| /* We have two physical storage locations: Rres (the "result" | |
| * register) and Rmul (the "multiple" register). | |
| * | |
| * On entry we have: | |
| * | |
| * Rres = g^0 = 1 (the identity element) | |
| * Rmul = g (the generator) | |
| * | |
| * For calculation purposes, define two virtual registers R[0] | |
| * and R[1], mapped to the underlying physical storage | |
| * locations via a boolean toggle state "t": | |
| * | |
| * R[t] -> Rres | |
| * R[~t] -> Rmul | |
| * | |
| * Define the initial toggle state to be t=0, so that we have: | |
| * | |
| * R[0] = g^0 = 1 (the identity element) | |
| * R[1] = g (the generator) | |
| * | |
| * The Montgomery ladder then iterates over each bit "b" of | |
| * the exponent "e" (from MSB down to LSB), computing: | |
| * | |
| * R[1] := R[0] * R[1], R[0] := R[0] * R[0] (if b=0) | |
| * R[0] := R[1] * R[0], R[1] := R[1] * R[1] (if b=1) | |
| * | |
| * i.e. | |
| * | |
| * R[~b] := R[b] * R[~b], R[b] := R[b] * R[b] | |
| * | |
| * To avoid data-dependent memory access patterns, we | |
| * implement this as: | |
| * | |
| * Rmul := Rres * Rmul | |
| * Rres := Rres * Rres | |
| * | |
| * and update the toggle state "t" (via constant-time | |
| * conditional swaps) as needed to ensure that R[b] always | |
| * maps to Rres and R[~b] always maps to Rmul. | |
| */ | |
| while ( bit-- ) { | |
| /* Update toggle state t := b | |
| * | |
| * If the new toggle state is not equal to the old | |
| * toggle state, then we must swap R[0] and R[1] (in | |
| * constant time). | |
| */ | |
| previous = toggle; | |
| toggle = bigint_bit_is_set ( exponent, bit ); | |
| bigint_swap ( result, multiple, ( toggle ^ previous ) ); | |
| /* Calculate Rmul = R[~b] := R[b] * R[~b] = Rres * Rmul */ | |
| op ( result->element, multiple->element, size, ctx, tmp ); | |
| /* Calculate Rres = R[b] := R[b] * R[b] = Rres * Rres */ | |
| op ( result->element, result->element, size, ctx, tmp ); | |
| } | |
| /* Reset toggle state to zero */ | |
| bigint_swap ( result, multiple, toggle ); | |
| } | |
| /** | |
| * Perform modular multiplication as part of a Montgomery ladder | |
| * | |
| * @v operand Element 0 of first input operand (may overlap result) | |
| * @v result Element 0 of second input operand and result | |
| * @v size Number of elements in operands and result | |
| * @v ctx Operation context (odd modulus, or NULL) | |
| * @v tmp Temporary working space | |
| */ | |
| void bigint_mod_exp_ladder ( const bigint_element_t *multiplier0, | |
| bigint_element_t *result0, unsigned int size, | |
| const void *ctx, void *tmp ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *multiplier = ( ( const void * ) multiplier0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) | |
| *result = ( ( void * ) result0 ); | |
| const bigint_t ( size ) __attribute__ (( may_alias )) | |
| *modulus = ( ( const void * ) ctx ); | |
| bigint_t ( size * 2 ) __attribute__ (( may_alias )) | |
| *product = ( ( void * ) tmp ); | |
| /* Multiply and reduce */ | |
| bigint_multiply ( result, multiplier, product ); | |
| if ( modulus ) { | |
| bigint_montgomery ( modulus, product, result ); | |
| } else { | |
| bigint_shrink ( product, result ); | |
| } | |
| } | |
| /** | |
| * Perform modular exponentiation of big integers | |
| * | |
| * @v base0 Element 0 of big integer base | |
| * @v modulus0 Element 0 of big integer modulus | |
| * @v exponent0 Element 0 of big integer exponent | |
| * @v result0 Element 0 of big integer to hold result | |
| * @v size Number of elements in base, modulus, and result | |
| * @v exponent_size Number of elements in exponent | |
| * @v tmp Temporary working space | |
| */ | |
| void bigint_mod_exp_raw ( const bigint_element_t *base0, | |
| const bigint_element_t *modulus0, | |
| const bigint_element_t *exponent0, | |
| bigint_element_t *result0, | |
| unsigned int size, unsigned int exponent_size, | |
| void *tmp ) { | |
| const bigint_t ( size ) __attribute__ (( may_alias )) *base = | |
| ( ( const void * ) base0 ); | |
| const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = | |
| ( ( const void * ) modulus0 ); | |
| const bigint_t ( exponent_size ) __attribute__ (( may_alias )) | |
| *exponent = ( ( const void * ) exponent0 ); | |
| bigint_t ( size ) __attribute__ (( may_alias )) *result = | |
| ( ( void * ) result0 ); | |
| const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); | |
| struct { | |
| struct { | |
| bigint_t ( size ) modulus; | |
| bigint_t ( size ) stash; | |
| }; | |
| union { | |
| bigint_t ( 2 * size ) full; | |
| bigint_t ( size ) low; | |
| } product; | |
| } *temp = tmp; | |
| const uint8_t one[1] = { 1 }; | |
| bigint_element_t submask; | |
| unsigned int subsize; | |
| unsigned int scale; | |
| unsigned int i; | |
| /* Sanity check */ | |
| assert ( sizeof ( *temp ) == bigint_mod_exp_tmp_len ( modulus ) ); | |
| /* Handle degenerate case of zero modulus */ | |
| if ( ! bigint_max_set_bit ( modulus ) ) { | |
| memset ( result, 0, sizeof ( *result ) ); | |
| return; | |
| } | |
| /* Factor modulus as (N * 2^scale) where N is odd */ | |
| bigint_copy ( modulus, &temp->modulus ); | |
| for ( scale = 0 ; ( ! bigint_bit_is_set ( &temp->modulus, 0 ) ) ; | |
| scale++ ) { | |
| bigint_shr ( &temp->modulus ); | |
| } | |
| subsize = ( ( scale + width - 1 ) / width ); | |
| submask = ( ( 1UL << ( scale % width ) ) - 1 ); | |
| if ( ! submask ) | |
| submask = ~submask; | |
| /* Calculate (R^2 mod N) */ | |
| bigint_reduce ( &temp->modulus, &temp->stash ); | |
| /* Initialise result = Montgomery(1, R^2 mod N) */ | |
| bigint_grow ( &temp->stash, &temp->product.full ); | |
| bigint_montgomery ( &temp->modulus, &temp->product.full, result ); | |
| /* Convert base into Montgomery form */ | |
| bigint_multiply ( base, &temp->stash, &temp->product.full ); | |
| bigint_montgomery ( &temp->modulus, &temp->product.full, | |
| &temp->stash ); | |
| /* Calculate x1 = base^exponent modulo N */ | |
| bigint_ladder ( result, &temp->stash, exponent, bigint_mod_exp_ladder, | |
| &temp->modulus, &temp->product ); | |
| /* Convert back out of Montgomery form */ | |
| bigint_grow ( result, &temp->product.full ); | |
| bigint_montgomery_relaxed ( &temp->modulus, &temp->product.full, | |
| result ); | |
| /* Handle even moduli via Garner's algorithm */ | |
| if ( subsize ) { | |
| const bigint_t ( subsize ) __attribute__ (( may_alias )) | |
| *subbase = ( ( const void * ) base ); | |
| bigint_t ( subsize ) __attribute__ (( may_alias )) | |
| *submodulus = ( ( void * ) &temp->modulus ); | |
| bigint_t ( subsize ) __attribute__ (( may_alias )) | |
| *substash = ( ( void * ) &temp->stash ); | |
| bigint_t ( subsize ) __attribute__ (( may_alias )) | |
| *subresult = ( ( void * ) result ); | |
| union { | |
| bigint_t ( 2 * subsize ) full; | |
| bigint_t ( subsize ) low; | |
| } __attribute__ (( may_alias )) | |
| *subproduct = ( ( void * ) &temp->product.full ); | |
| /* Calculate x2 = base^exponent modulo 2^k */ | |
| bigint_init ( substash, one, sizeof ( one ) ); | |
| bigint_copy ( subbase, submodulus ); | |
| bigint_ladder ( substash, submodulus, exponent, | |
| bigint_mod_exp_ladder, NULL, subproduct ); | |
| /* Reconstruct N */ | |
| bigint_copy ( modulus, &temp->modulus ); | |
| for ( i = 0 ; i < scale ; i++ ) | |
| bigint_shr ( &temp->modulus ); | |
| /* Calculate N^-1 modulo 2^k */ | |
| bigint_mod_invert ( submodulus, &subproduct->low ); | |
| bigint_copy ( &subproduct->low, submodulus ); | |
| /* Calculate y = (x2 - x1) * N^-1 modulo 2^k */ | |
| bigint_subtract ( subresult, substash ); | |
| bigint_multiply ( substash, submodulus, &subproduct->full ); | |
| subproduct->low.element[ subsize - 1 ] &= submask; | |
| bigint_grow ( &subproduct->low, &temp->stash ); | |
| /* Reconstruct N */ | |
| bigint_mod_invert ( submodulus, &subproduct->low ); | |
| bigint_copy ( &subproduct->low, submodulus ); | |
| /* Calculate x = x1 + N * y */ | |
| bigint_multiply ( &temp->modulus, &temp->stash, | |
| &temp->product.full ); | |
| bigint_add ( &temp->product.low, result ); | |
| } | |
| } |