]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Eliminate temporary working space for bigint_mod_invert()
authorMichael Brown <mcb30@ipxe.org>
Wed, 27 Nov 2024 12:51:04 +0000 (12:51 +0000)
committerMichael Brown <mcb30@ipxe.org>
Wed, 27 Nov 2024 13:05:18 +0000 (13:05 +0000)
With a slight modification to the algorithm to ignore bits of the
residue that can never contribute to the result, it is possible to
reuse the as-yet uncalculated portions of the inverse to hold the
residue.  This removes the requirement for additional temporary
working space.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/bigint.c
src/include/ipxe/bigint.h
src/tests/bigint_test.c

index 4b37c062b80d9c86c9602057851d685955102936..735fcdf6195b859d094da9cea0cf977488517c1b 100644 (file)
@@ -287,27 +287,22 @@ void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0,
  * @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
- * @v tmp              Temporary working space
  */
 void bigint_mod_invert_raw ( const bigint_element_t *invertend0,
-                            bigint_element_t *inverse0,
-                            unsigned int size, void *tmp ) {
+                            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 );
-       struct {
-               bigint_t ( size ) residue;
-       } *temp = tmp;
-       const unsigned int width = ( 8 * sizeof ( bigint_element_t ) );
+       bigint_element_t accum;
+       bigint_element_t bit;
        unsigned int i;
 
        /* Sanity check */
-       assert ( invertend->element[0] & 1 );
+       assert ( bigint_bit_is_set ( invertend, 0 ) );
 
-       /* Initialise temporary working space and output value */
-       memset ( &temp->residue, 0xff, sizeof ( temp->residue ) );
-       memset ( inverse, 0, sizeof ( *inverse ) );
+       /* Initialise output */
+       memset ( inverse, 0xff, sizeof ( *inverse ) );
 
        /* Compute inverse modulo 2^(width)
         *
@@ -315,23 +310,47 @@ void bigint_mod_invert_raw ( const bigint_element_t *invertend0,
         * presented in "A New Algorithm for Inversion mod p^k (Koç,
         * 2017)".
         *
-        * Each 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).
+        * 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 = 0 ; i < ( 8 * sizeof ( *inverse ) ) ; i++ ) {
-               if ( temp->residue.element[0] & 1 ) {
-                       inverse->element[ i / width ] |=
-                               ( 1UL << ( i % width ) );
-                       bigint_add ( invertend, &temp->residue );
+       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 );
                }
-               bigint_shr ( &temp->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;
        }
 }
 
index 330d7deec699995f47bf36dc1d58a07768e2428c..e55c536c761738c04d02ca0b9193caa7f5de98cc 100644 (file)
@@ -242,30 +242,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
        } while ( 0 )
 
 /**
- * Compute inverse of odd big integer modulo its own size
+ * Compute inverse of odd big integer modulo any power of two
  *
  * @v invertend                Odd big integer to be inverted
  * @v inverse          Big integer to hold result
- * @v tmp              Temporary working space
  */
-#define bigint_mod_invert( invertend, inverse, tmp ) do {              \
-       unsigned int size = bigint_size (invertend);                    \
+#define bigint_mod_invert( invertend, inverse ) do {                   \
+       unsigned int size = bigint_size ( invertend );                  \
        bigint_mod_invert_raw ( (invertend)->element,                   \
-                               (inverse)->element, size, tmp );        \
+                               (inverse)->element, size );             \
        } while ( 0 )
 
-/**
- * Calculate temporary working space required for modular inversion
- *
- * @v invertend                Odd big integer to be inverted
- * @ret len            Length of temporary working space
- */
-#define bigint_mod_invert_tmp_len( invertend ) ( {                     \
-       unsigned int size = bigint_size (invertend);                    \
-       sizeof ( struct {                                               \
-               bigint_t ( size ) temp_residue;                         \
-       } ); } )
-
 /**
  * Perform modular multiplication of big integers
  *
@@ -408,8 +395,7 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0,
 void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0,
                         unsigned int size );
 void bigint_mod_invert_raw ( const bigint_element_t *invertend0,
-                            bigint_element_t *inverse0,
-                            unsigned int size, void *tmp );
+                            bigint_element_t *inverse0, unsigned int size );
 void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
                               const bigint_element_t *multiplier0,
                               const bigint_element_t *modulus0,
index 61f78fff992a3e842610341edbcb9b3f6b228bfc..608d8e874ca494270fc4e1fd2c20d7fc2ec3bf7f 100644 (file)
@@ -197,13 +197,13 @@ void bigint_reduce_sample ( bigint_element_t *modulus0,
 
 void bigint_mod_invert_sample ( const bigint_element_t *invertend0,
                                bigint_element_t *inverse0,
-                               unsigned int size, void *tmp ) {
+                               unsigned int size ) {
        const bigint_t ( size ) __attribute__ (( may_alias ))
                *invertend = ( ( const void * ) invertend0 );
        bigint_t ( size ) __attribute__ (( may_alias ))
                *inverse = ( ( void * ) inverse0 );
 
-       bigint_mod_invert ( invertend, inverse, tmp );
+       bigint_mod_invert ( invertend, inverse );
 }
 
 void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0,
@@ -600,8 +600,6 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0,
                bigint_required_size ( sizeof ( invertend_raw ) );      \
        bigint_t ( size ) invertend_temp;                               \
        bigint_t ( size ) inverse_temp;                                 \
-       size_t tmp_len = bigint_mod_invert_tmp_len ( &invertend_temp ); \
-       uint8_t tmp[tmp_len];                                           \
        {} /* Fix emacs alignment */                                    \
                                                                        \
        assert ( bigint_size ( &invertend_temp ) ==                     \
@@ -610,7 +608,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0,
                      sizeof ( invertend_raw ) );                       \
        DBG ( "Modular invert:\n" );                                    \
        DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) );      \
-       bigint_mod_invert ( &invertend_temp, &inverse_temp, tmp );      \
+       bigint_mod_invert ( &invertend_temp, &inverse_temp );           \
        DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) );          \
        bigint_done ( &inverse_temp, inverse_raw,                       \
                      sizeof ( inverse_raw ) );                         \
@@ -1827,6 +1825,10 @@ static void bigint_test_exec ( void ) {
                                        0xff, 0xff ),
                               BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                                        0xff, 0xff ) );
+       bigint_mod_invert_ok ( BIGINT ( 0xa4, 0xcb, 0xbc, 0xc9, 0x9f, 0x7a,
+                                       0x65, 0xbf ),
+                              BIGINT ( 0xb9, 0xd5, 0xf4, 0x88, 0x0b, 0xf8,
+                                       0x8a, 0x3f ) );
        bigint_mod_invert_ok ( BIGINT ( 0x95, 0x6a, 0xc5, 0xe7, 0x2e, 0x5b,
                                        0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d,
                                        0xf4, 0x5a, 0x48, 0xc1 ),
@@ -1839,6 +1841,18 @@ static void bigint_test_exec ( void ) {
                               BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4,
                                        0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf,
                                        0x5f, 0xe2, 0x21, 0xcd ) );
+       bigint_mod_invert_ok ( BIGINT ( 0xb9, 0xbb, 0x7f, 0x9c, 0x7a, 0x32,
+                                       0x43, 0xed, 0x9d, 0xd4, 0x0d, 0x6f,
+                                       0x32, 0xfa, 0x4b, 0x62, 0x38, 0x3a,
+                                       0xbf, 0x4c, 0xbd, 0xa8, 0x47, 0xce,
+                                       0xa2, 0x30, 0x34, 0xe0, 0x2c, 0x09,
+                                       0x14, 0x89 ),
+                              BIGINT ( 0xfc, 0x05, 0xc4, 0x2a, 0x90, 0x99,
+                                       0x82, 0xf8, 0x81, 0x1d, 0x87, 0xb8,
+                                       0xca, 0xe4, 0x95, 0xe2, 0xac, 0x18,
+                                       0xb3, 0xe1, 0x3e, 0xc6, 0x5a, 0x03,
+                                       0x51, 0x6f, 0xb7, 0xe3, 0xa5, 0xd6,
+                                       0xa1, 0xb9 ) );
        bigint_mod_multiply_ok ( BIGINT ( 0x37 ),
                                 BIGINT ( 0x67 ),
                                 BIGINT ( 0x3f ),