]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Add big-integer library for RSA calculations
authorMichael Brown <mcb30@ipxe.org>
Tue, 13 Mar 2012 16:35:21 +0000 (16:35 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 13 Mar 2012 23:27:30 +0000 (23:27 +0000)
RSA requires modular exponentiation using arbitrarily large integers.
Given the sizes of the modulus and exponent, all required calculations
can be done without any further dynamic storage allocation.  The x86
architecture allows for efficient large integer support via inline
assembly using the instructions that take advantage of the carry flag
(e.g. "adcl", "rcrl").

This implemention is approximately 80% smaller than the (more generic)
AXTLS implementation.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/x86/core/x86_bigint.c [new file with mode: 0644]
src/arch/x86/include/bits/bigint.h [new file with mode: 0644]
src/crypto/axtls/axtls_bigint.c [moved from src/crypto/axtls/bigint.c with 100% similarity]
src/crypto/bigint.c [new file with mode: 0644]
src/include/ipxe/bigint.h [new file with mode: 0644]

diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c
new file mode 100644 (file)
index 0000000..cb6c67b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/bigint.h>
+
+/** @file
+ *
+ * Big integer support
+ */
+
+/**
+ * Multiply big integers
+ *
+ * @v multiplicand0    Element 0 of big integer to be multiplied
+ * @v multiplier0      Element 0 of big integer to be multiplied
+ * @v result0          Element 0 of big integer to hold result
+ * @v size             Number of elements
+ */
+void bigint_multiply_raw ( const uint32_t *multiplicand0,
+                          const uint32_t *multiplier0,
+                          uint32_t *result0, unsigned int size ) {
+       const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
+               ( ( const void * ) multiplicand0 );
+       const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
+               ( ( const void * ) multiplier0 );
+       bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
+               ( ( void * ) result0 );
+       unsigned int i;
+       unsigned int j;
+       uint32_t multiplicand_element;
+       uint32_t multiplier_element;
+       uint32_t *result_elements;
+       uint32_t discard_a;
+       uint32_t discard_d;
+       long index;
+
+       /* Zero result */
+       memset ( result, 0, sizeof ( *result ) );
+
+       /* Multiply integers one element at a time */
+       for ( i = 0 ; i < size ; i++ ) {
+               multiplicand_element = multiplicand->element[i];
+               for ( j = 0 ; j < size ; j++ ) {
+                       multiplier_element = multiplier->element[j];
+                       result_elements = &result->element[ i + j ];
+                       /* Perform a single multiply, and add the
+                        * resulting double-element into the result,
+                        * carrying as necessary.  The carry can
+                        * never overflow beyond the end of the
+                        * result, since:
+                        *
+                        *     a < 2^{n}, b < 2^{n} => ab < 2^{2n}
+                        */
+                       __asm__ __volatile__ ( "mull %4\n\t"
+                                              "addl %%eax, (%5,%2,4)\n\t"
+                                              "adcl %%edx, 4(%5,%2,4)\n\t"
+                                              "\n1:\n\t"
+                                              "adcl $0, 8(%5,%2,4)\n\t"
+                                              "inc %2\n\t"
+                                                      /* Does not affect CF */
+                                              "jc 1b\n\t"
+                                              : "=&a" ( discard_a ),
+                                                "=&d" ( discard_d ),
+                                                "=&r" ( index )
+                                              : "0" ( multiplicand_element ),
+                                                "g" ( multiplier_element ),
+                                                "r" ( result_elements ),
+                                                "2" ( 0 ) );
+               }
+       }
+}
diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h
new file mode 100644 (file)
index 0000000..4c9aed6
--- /dev/null
@@ -0,0 +1,318 @@
+#ifndef _BITS_BIGINT_H
+#define _BITS_BIGINT_H
+
+/** @file
+ *
+ * Big integer support
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+
+/** Element of a big integer */
+typedef uint32_t bigint_element_t;
+
+/**
+ * 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
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_init_raw ( uint32_t *value0, unsigned int size,
+                 const void *data, size_t len ) {
+       long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
+       void *discard_D;
+       long discard_c;
+
+       /* Copy raw data in reverse order, padding with zeros */
+       __asm__ __volatile__ ( "\n1:\n\t"
+                              "movb -1(%2,%1), %%al\n\t"
+                              "stosb\n\t"
+                              "loop 1b\n\t"
+                              "xorl %%eax, %%eax\n\t"
+                              "mov %3, %1\n\t"
+                              "rep stosb\n\t"
+                              : "=&D" ( discard_D ), "=&c" ( discard_c )
+                              : "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
+                                "1" ( len )
+                              : "eax" );
+}
+
+/**
+ * Add big integers
+ *
+ * @v addend0          Element 0 of big integer to add
+ * @v value0           Element 0 of big integer to be added to
+ * @v size             Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
+                unsigned int size ) {
+       long index;
+       void *discard_S;
+       long discard_c;
+
+       __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
+                              "\n1:\n\t"
+                              "lodsl\n\t"
+                              "adcl %%eax, (%3,%0,4)\n\t"
+                              "inc %0\n\t" /* Does not affect CF */
+                              "loop 1b\n\t"
+                              : "=&r" ( index ), "=&S" ( discard_S ),
+                                "=&c" ( discard_c )
+                              : "r" ( value0 ), "1" ( addend0 ), "2" ( size )
+                              : "eax" );
+}
+
+/**
+ * Subtract big integers
+ *
+ * @v subtrahend0      Element 0 of big integer to subtract
+ * @v value0           Element 0 of big integer to be subtracted from
+ * @v size             Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
+                     unsigned int size ) {
+       long index;
+       void *discard_S;
+       long discard_c;
+
+       __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
+                              "\n1:\n\t"
+                              "lodsl\n\t"
+                              "sbbl %%eax, (%3,%0,4)\n\t"
+                              "inc %0\n\t" /* Does not affect CF */
+                              "loop 1b\n\t"
+                              : "=&r" ( index ), "=&S" ( discard_S ),
+                                "=&c" ( discard_c )
+                              : "r" ( value0 ), "1" ( subtrahend0 ),
+                                "2" ( size )
+                              : "eax" );
+}
+
+/**
+ * Rotate big integer left
+ *
+ * @v value0           Element 0 of big integer
+ * @v size             Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
+       long index;
+       long discard_c;
+
+       __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
+                              "\n1:\n\t"
+                              "rcll $1, (%2,%0,4)\n\t"
+                              "inc %0\n\t" /* Does not affect CF */
+                              "loop 1b\n\t"
+                              : "=&r" ( index ), "=&c" ( discard_c )
+                              : "r" ( value0 ), "1" ( size ) );
+}
+
+/**
+ * Rotate big integer right
+ *
+ * @v value0           Element 0 of big integer
+ * @v size             Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
+       long discard_c;
+
+       __asm__ __volatile__ ( "clc\n\t"
+                              "\n1:\n\t"
+                              "rcrl $1, -4(%1,%0,4)\n\t"
+                              "loop 1b\n\t"
+                              : "=&c" ( discard_c )
+                              : "r" ( value0 ), "0" ( size ) );
+}
+
+/**
+ * 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
+ */
+static inline __attribute__ (( always_inline, pure )) int
+bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
+       void *discard_D;
+       long discard_c;
+       int result;
+
+       __asm__ __volatile__ ( "xor %0, %0\n\t" /* Set ZF */
+                              "repe scasl\n\t"
+                              "sete %b0\n\t"
+                              : "=&a" ( result ), "=&D" ( discard_D ),
+                                "=&c" ( discard_c )
+                              : "1" ( value0 ), "2" ( size ) );
+       return result;
+}
+
+/**
+ * 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
+ */
+static inline __attribute__ (( always_inline, pure )) int
+bigint_is_geq_raw ( const uint32_t *value0, const uint32_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 );
+       void *discard_S;
+       void *discard_D;
+       long discard_c;
+       int result;
+
+       __asm__ __volatile__ ( "std\n\t"
+                              "\n1:\n\t"
+                              "lodsl\n\t"
+                              "scasl\n\t"
+                              "loope 1b\n\t"
+                              "setae %b0\n\t"
+                              "cld\n\t"
+                              : "=r" ( result ), "=&S" ( discard_S ),
+                                "=&D" ( discard_D ), "=&c" ( discard_c )
+                              : "0" ( 0 ), "1" ( &value->element[ size - 1 ] ),
+                                "2" ( &reference->element[ size - 1 ] ),
+                                "3" ( size )
+                              : "eax" );
+       return result;
+}
+
+/**
+ * Test if bit is set in big integer
+ *
+ * @v value0           Element 0 of big integer
+ * @v size             Number of elements
+ * @v bit              Bit to test
+ * @ret is_set         Bit is set
+ */
+static inline __attribute__ (( always_inline )) int
+bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
+                       unsigned int bit ) {
+       const bigint_t ( size ) __attribute__ (( may_alias )) *value =
+               ( ( const void * ) value0 );
+       unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
+       unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
+
+       return ( value->element[index] & ( 1 << subindex ) );
+}
+
+/**
+ * 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)
+ */
+static inline __attribute__ (( always_inline )) int
+bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
+       long discard_c;
+       int result;
+
+       __asm__ __volatile__ ( "\n1:\n\t"
+                              "bsrl -4(%2,%1,4), %0\n\t"
+                              "loopz 1b\n\t"
+                              "rol %1\n\t" /* Does not affect ZF */
+                              "rol %1\n\t"
+                              "leal 1(%k0,%k1,8), %k0\n\t"
+                              "jnz 2f\n\t"
+                              "xor %0, %0\n\t"
+                              "\n2:\n\t"
+                              : "=&r" ( result ), "=&c" ( discard_c )
+                              : "r" ( value0 ), "1" ( size ) );
+       return result;
+}
+
+/**
+ * Grow big integer
+ *
+ * @v source0          Element 0 of source big integer
+ * @v source_size      Number of elements in source big integer
+ * @v dest0            Element 0 of destination big integer
+ * @v dest_size                Number of elements in destination big integer
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
+                 uint32_t *dest0, unsigned int dest_size ) {
+       long pad_size = ( dest_size - source_size );
+       void *discard_D;
+       void *discard_S;
+       long discard_c;
+
+       __asm__ __volatile__ ( "rep movsl\n\t"
+                              "xorl %%eax, %%eax\n\t"
+                              "mov %3, %2\n\t"
+                              "rep stosl\n\t"
+                              : "=&D" ( discard_D ), "=&S" ( discard_S ),
+                                "=&c" ( discard_c )
+                              : "g" ( pad_size ), "0" ( dest0 ),
+                                "1" ( source0 ), "2" ( source_size )
+                              : "eax" );
+}
+
+/**
+ * Shrink big integer
+ *
+ * @v source0          Element 0 of source big integer
+ * @v source_size      Number of elements in source big integer
+ * @v dest0            Element 0 of destination big integer
+ * @v dest_size                Number of elements in destination big integer
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
+                   uint32_t *dest0, unsigned int dest_size ) {
+       void *discard_D;
+       void *discard_S;
+       long discard_c;
+
+       __asm__ __volatile__ ( "rep movsl\n\t"
+                              : "=&D" ( discard_D ), "=&S" ( discard_S ),
+                                "=&c" ( discard_c )
+                              : "0" ( dest0 ), "1" ( source0 ),
+                                "2" ( dest_size )
+                              : "eax" );
+}
+
+/**
+ * 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
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
+                 void *out, size_t len ) {
+       void *discard_D;
+       long discard_c;
+
+       /* Copy raw data in reverse order */
+       __asm__ __volatile__ ( "\n1:\n\t"
+                              "movb -1(%2,%1), %%al\n\t"
+                              "stosb\n\t"
+                              "loop 1b\n\t"
+                              : "=&D" ( discard_D ), "=&c" ( discard_c )
+                              : "r" ( value0 ), "0" ( out ), "1" ( len )
+                              : "eax" );
+}
+
+extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
+                                 const uint32_t *multiplier0,
+                                 uint32_t *value0, unsigned int size );
+
+#endif /* _BITS_BIGINT_H */
diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c
new file mode 100644 (file)
index 0000000..c3edec9
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/bigint.h>
+
+/** @file
+ *
+ * Big integer support
+ */
+
+/**
+ * Perform modular multiplication of big integers
+ *
+ * @v multiplicand0    Element 0 of big integer to be multiplied
+ * @v multiplier0      Element 0 of big integer to be multiplied
+ * @v modulus0         Element 0 of big integer modulus
+ * @v result0          Element 0 of big integer to hold result
+ */
+void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
+                              const bigint_element_t *multiplier0,
+                              const bigint_element_t *modulus0,
+                              bigint_element_t *result0,
+                              unsigned int size ) {
+       const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
+               ( ( const void * ) multiplicand0 );
+       const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
+               ( ( const void * ) multiplier0 );
+       const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
+               ( ( const void * ) modulus0 );
+       bigint_t ( size ) __attribute__ (( may_alias )) *result =
+               ( ( void * ) result0 );
+       bigint_t ( size * 2 ) temp_result;
+       bigint_t ( size * 2 ) temp_modulus;
+       int rotation;
+       int i;
+
+       /* Perform multiplication */
+       bigint_multiply ( multiplicand, multiplier, &temp_result );
+
+       /* Rescale modulus to match result */
+       bigint_grow ( modulus, &temp_modulus );
+       rotation = ( bigint_max_set_bit ( &temp_result ) -
+                    bigint_max_set_bit ( &temp_modulus ) );
+       for ( i = 0 ; i < rotation ; i++ )
+               bigint_rol ( &temp_modulus );
+
+       /* Subtract multiples of modulus */
+       for ( i = 0 ; i <= rotation ; i++ ) {
+               if ( bigint_is_geq ( &temp_result, &temp_modulus ) )
+                       bigint_subtract ( &temp_modulus, &temp_result );
+               bigint_ror ( &temp_modulus );
+       }
+
+       /* Resize result */
+       bigint_shrink ( &temp_result, result );
+
+       /* Sanity check */
+       assert ( bigint_is_geq ( modulus, 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
+ */
+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 ) {
+       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 );
+       bigint_t ( size ) temp_base;
+       bigint_t ( exponent_size ) temp_exponent;
+       static const uint8_t start[1] = { 0x01 };
+
+       memcpy ( &temp_base, base, sizeof ( temp_base ) );
+       memcpy ( &temp_exponent, exponent, sizeof ( temp_exponent ) );
+       bigint_init ( result, start, sizeof ( start ) );
+
+       while ( ! bigint_is_zero ( &temp_exponent ) ) {
+               if ( bigint_bit_is_set ( &temp_exponent, 0 ) ) {
+                       bigint_mod_multiply ( result, &temp_base,
+                                             modulus, result );
+               }
+               bigint_ror ( &temp_exponent );
+               bigint_mod_multiply ( &temp_base, &temp_base, modulus,
+                                     &temp_base );
+       }
+}
diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h
new file mode 100644 (file)
index 0000000..a21b3e5
--- /dev/null
@@ -0,0 +1,268 @@
+#ifndef _IPXE_BIGINT_H
+#define _IPXE_BIGINT_H
+
+/** @file
+ *
+ * Big integer support
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Define a big-integer type
+ *
+ * @v size             Number of elements
+ * @ret bigint_t       Big integer type
+ */
+#define bigint_t( size )                                               \
+       struct {                                                        \
+               bigint_element_t element[ (size) ];                     \
+       }
+
+/**
+ * Determine number of elements required for a big-integer type
+ *
+ * @v len              Maximum length of big integer, in bytes
+ * @ret size           Number of elements
+ */
+#define bigint_required_size( len )                                    \
+       ( ( (len) + sizeof ( bigint_element_t ) - 1 ) /                 \
+         sizeof ( bigint_element_t ) )
+
+/**
+ * Determine number of elements in big-integer type
+ *
+ * @v bigint           Big integer
+ * @ret size           Number of elements
+ */
+#define bigint_size( bigint )                                          \
+       ( sizeof ( *(bigint) ) / sizeof ( (bigint)->element[0] ) )
+
+/**
+ * Initialise big integer
+ *
+ * @v value            Big integer to initialise
+ * @v data             Raw data
+ * @v len              Length of raw data
+ */
+#define bigint_init( value, data, len ) do {                           \
+       unsigned int size = bigint_size (value);                        \
+       assert ( (len) <= ( size * sizeof ( (value)->element[0] ) ) );  \
+       bigint_init_raw ( (value)->element, size, (data), (len) );      \
+       } while ( 0 )
+
+/**
+ * Finalise big integer
+ *
+ * @v value            Big integer to finalise
+ * @v out              Output buffer
+ * @v len              Length of output buffer
+ */
+#define bigint_done( value, out, len ) do {                            \
+       unsigned int size = bigint_size (value);                        \
+       bigint_done_raw ( (value)->element, size, (out), (len) );       \
+       } while ( 0 )
+
+/**
+ * Add big integers
+ *
+ * @v addend           Big integer to add
+ * @v value            Big integer to be added to
+ */
+#define bigint_add( addend, value ) do {                               \
+       unsigned int size = bigint_size (addend);                       \
+       bigint_add_raw ( (addend)->element, (value)->element, size );   \
+       } while ( 0 )
+
+/**
+ * Subtract big integers
+ *
+ * @v subtrahend       Big integer to subtract
+ * @v value            Big integer to be subtracted from
+ */
+#define bigint_subtract( subtrahend, value ) do {                      \
+       unsigned int size = bigint_size (subtrahend);                   \
+       bigint_subtract_raw ( (subtrahend)->element, (value)->element,  \
+                             size );                                   \
+       } while ( 0 )
+
+/**
+ * Rotate big integer left
+ *
+ * @v value            Big integer
+ */
+#define bigint_rol( value ) do {                                       \
+       unsigned int size = bigint_size (value);                        \
+       bigint_rol_raw ( (value)->element, size );                      \
+       } while ( 0 )
+
+/**
+ * Rotate big integer right
+ *
+ * @v value            Big integer
+ */
+#define bigint_ror( value ) do {                                       \
+       unsigned int size = bigint_size (value);                        \
+       bigint_ror_raw ( (value)->element, size );                      \
+       } while ( 0 )
+
+/**
+ * Test if big integer is equal to zero
+ *
+ * @v value            Big integer
+ * @v size             Number of elements
+ * @ret is_zero                Big integer is equal to zero
+ */
+#define bigint_is_zero( value ) ( {                                    \
+       unsigned int size = bigint_size (value);                        \
+       bigint_is_zero_raw ( (value)->element, size ); } )
+
+/**
+ * Compare big integers
+ *
+ * @v value            Big integer
+ * @v reference                Reference big integer
+ * @ret geq            Big integer is greater than or equal to the reference
+ */
+#define bigint_is_geq( value, reference ) ( {                          \
+       unsigned int size = bigint_size (value);                        \
+       bigint_is_geq_raw ( (value)->element, (reference)->element,     \
+                           size ); } )
+
+/**
+ * Test if bit is set in big integer
+ *
+ * @v value            Big integer
+ * @v bit              Bit to test
+ * @ret is_set         Bit is set
+ */
+#define bigint_bit_is_set( value, bit ) ( {                            \
+       unsigned int size = bigint_size (value);                        \
+       bigint_bit_is_set_raw ( (value)->element, size, bit ); } )
+
+/**
+ * Find highest bit set in big integer
+ *
+ * @v value            Big integer
+ * @ret max_bit                Highest bit set + 1 (or 0 if no bits set)
+ */
+#define bigint_max_set_bit( value ) ( {                                        \
+       unsigned int size = bigint_size (value);                        \
+       bigint_max_set_bit_raw ( (value)->element, size ); } )
+
+/**
+ * Grow big integer
+ *
+ * @v source           Source big integer
+ * @v dest             Destination big integer
+ */
+#define bigint_grow( source, dest ) do {                               \
+       unsigned int source_size = bigint_size (source);                \
+       unsigned int dest_size = bigint_size (dest);                    \
+       bigint_grow_raw ( (source)->element, source_size,               \
+                         (dest)->element, dest_size );                 \
+       } while ( 0 )
+
+/**
+ * Shrink big integer
+ *
+ * @v source           Source big integer
+ * @v dest             Destination big integer
+ */
+#define bigint_shrink( source, dest ) do {                             \
+       unsigned int source_size = bigint_size (source);                \
+       unsigned int dest_size = bigint_size (dest);                    \
+       bigint_shrink_raw ( (source)->element, source_size,             \
+                           (dest)->element, dest_size );               \
+       } while ( 0 )
+
+/**
+ * Multiply big integers
+ *
+ * @v multiplicand     Big integer to be multiplied
+ * @v multiplier       Big integer to be multiplied
+ * @v result           Big integer to hold result
+ */
+#define bigint_multiply( multiplicand, multiplier, result ) do {       \
+       unsigned int size = bigint_size (multiplicand);                 \
+       bigint_multiply_raw ( (multiplicand)->element,                  \
+                             (multiplier)->element, (result)->element, \
+                             size );                                   \
+       } while ( 0 )
+
+/**
+ * Perform modular multiplication of big integers
+ *
+ * @v multiplicand     Big integer to be multiplied
+ * @v multiplier       Big integer to be multiplied
+ * @v modulus          Big integer modulus
+ * @v result           Big integer to hold result
+ */
+#define bigint_mod_multiply( multiplicand, multiplier, modulus,                \
+                            result ) do {                              \
+       unsigned int size = bigint_size (multiplicand);                 \
+       bigint_mod_multiply_raw ( (multiplicand)->element,              \
+                                 (multiplier)->element,                \
+                                 (modulus)->element,                   \
+                                 (result)->element, size );            \
+       } while ( 0 )
+
+/**
+ * Perform modular exponentiation of big integers
+ *
+ * @v base             Big integer base
+ * @v modulus          Big integer modulus
+ * @v exponent         Big integer exponent
+ * @v result           Big integer to hold result
+ */
+#define bigint_mod_exp( base, modulus, exponent, result ) do {         \
+       unsigned int size = bigint_size (base);                         \
+       unsigned int exponent_size = bigint_size (exponent);            \
+       bigint_mod_exp_raw ( (base)->element, (modulus)->element,       \
+                         (exponent)->element, (result)->element,       \
+                         size, exponent_size );                        \
+       } while ( 0 )
+
+#include <bits/bigint.h>
+
+void bigint_init_raw ( bigint_element_t *value0, unsigned int size,
+                      const void *data, size_t len );
+void bigint_done_raw ( const bigint_element_t *value0, unsigned int size,
+                      void *out, size_t len );
+void bigint_add_raw ( const bigint_element_t *addend0,
+                     bigint_element_t *value0, unsigned int size );
+void bigint_subtract_raw ( const bigint_element_t *subtrahend0,
+                          bigint_element_t *value0, unsigned int size );
+void bigint_rol_raw ( bigint_element_t *value0, unsigned int size );
+void bigint_ror_raw ( bigint_element_t *value0, unsigned int size );
+int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size );
+int bigint_is_geq_raw ( const bigint_element_t *value0,
+                       const bigint_element_t *reference0,
+                       unsigned int size );
+int bigint_bit_is_set_raw ( const bigint_element_t *value0, unsigned int size,
+                           unsigned int bit );
+int bigint_max_set_bit_raw ( const bigint_element_t *value0,
+                            unsigned int size );
+void bigint_grow_raw ( const bigint_element_t *source0,
+                      unsigned int source_size, bigint_element_t *dest0,
+                      unsigned int dest_size );
+void bigint_shrink_raw ( const bigint_element_t *source0,
+                        unsigned int source_size, bigint_element_t *dest0,
+                        unsigned int dest_size );
+void bigint_multiply_raw ( const bigint_element_t *multiplicand0,
+                          const bigint_element_t *multiplier0,
+                          bigint_element_t *result0,
+                          unsigned int size );
+void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
+                              const bigint_element_t *multiplier0,
+                              const bigint_element_t *modulus0,
+                              bigint_element_t *result0,
+                              unsigned int size );
+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 );
+
+#endif /* _IPXE_BIGINT_H */