[crypto] Use generic implementations of slow-path big integer functions

In the original big integer implementation, big integers were entirely
opaque to the caller and only the architecture-dependent code knew any
details of the internal structure.

This has long since ceased to be the case: for the sake of arithmetic
efficiency, many portions of the codebase now presume that big
integers are represented as an array of elements, with each element
being a native-endian unsigned value (with the precise type being
chosen by the architecture-specific header file) and with the least
significant element being first in the array.

The functions bigint_init(), bigint_done(), bigint_is_zero(),
bigint_is_geq(), and bigint_max_bit_set() are never used on fast code
paths, and most architectures use a generic C implementation of these
functions.

Provide generic implementations of these slow-path functions to be
used on all architectures.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h
index 988bef5..da6cfbf 100644
--- a/src/arch/arm32/include/bits/bigint.h
+++ b/src/arch/arm32/include/bits/bigint.h
@@ -10,34 +10,11 @@
 
 #include <stdint.h>
 #include <string.h>
-#include <strings.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 ) {
-	size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
-	uint8_t *value_byte = ( ( void * ) value0 );
-	const uint8_t *data_byte = ( data + len );
-
-	/* Copy raw data in reverse order, padding with zeros */
-	while ( len-- )
-		*(value_byte++) = *(--data_byte);
-	while ( pad_len-- )
-		*(value_byte++) = 0;
-}
-
-/**
  * Add big integers
  *
  * @v addend0		Element 0 of big integer to add
@@ -183,76 +160,6 @@
 }
 
 /**
- * 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 ) {
-	const uint32_t *value = value0;
-	uint32_t value_i;
-
-	do {
-		value_i = *(value++);
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return ( value_i == 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
- */
-static inline __attribute__ (( always_inline, pure )) int
-bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
-		    unsigned int size ) {
-	const uint32_t *value = ( value0 + size );
-	const uint32_t *reference = ( reference0 + size );
-	uint32_t value_i;
-	uint32_t reference_i;
-
-	do {
-		value_i = *(--value);
-		reference_i = *(--reference);
-		if ( value_i != reference_i )
-			break;
-	} while ( --size );
-
-	return ( value_i >= reference_i );
-}
-
-/**
- * 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 ) {
-	const uint32_t *value = ( value0 + size );
-	int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
-	uint32_t value_i;
-
-	do {
-		value_i = *(--value);
-		max_bit -= ( 32 - fls ( value_i ) );
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return max_bit;
-}
-
-/**
  * Grow big integer
  *
  * @v source0		Element 0 of source big integer
@@ -285,25 +192,6 @@
 }
 
 /**
- * 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 ) {
-	const uint8_t *value_byte = ( ( const void * ) value0 );
-	uint8_t *out_byte = ( out + len );
-
-	/* Copy raw data in reverse order */
-	while ( len-- )
-		*(--out_byte) = *(value_byte++);
-}
-
-/**
  * Multiply big integer elements
  *
  * @v multiplicand	Multiplicand element
diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h
index a4c351c..8d7a795 100644
--- a/src/arch/arm64/include/bits/bigint.h
+++ b/src/arch/arm64/include/bits/bigint.h
@@ -11,34 +11,11 @@
 
 #include <stdint.h>
 #include <string.h>
-#include <strings.h>
 
 /** Element of a big integer */
 typedef uint64_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 ( uint64_t *value0, unsigned int size,
-		  const void *data, size_t len ) {
-	size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
-	uint8_t *value_byte = ( ( void * ) value0 );
-	const uint8_t *data_byte = ( data + len );
-
-	/* Copy raw data in reverse order, padding with zeros */
-	while ( len-- )
-		*(value_byte++) = *(--data_byte);
-	while ( pad_len-- )
-		*(value_byte++) = 0;
-}
-
-/**
  * Add big integers
  *
  * @v addend0		Element 0 of big integer to add
@@ -184,76 +161,6 @@
 }
 
 /**
- * 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 uint64_t *value0, unsigned int size ) {
-	const uint64_t *value = value0;
-	uint64_t value_i;
-
-	do {
-		value_i = *(value++);
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return ( value_i == 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
- */
-static inline __attribute__ (( always_inline, pure )) int
-bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0,
-		    unsigned int size ) {
-	const uint64_t *value = ( value0 + size );
-	const uint64_t *reference = ( reference0 + size );
-	uint64_t value_i;
-	uint64_t reference_i;
-
-	do {
-		value_i = *(--value);
-		reference_i = *(--reference);
-		if ( value_i != reference_i )
-			break;
-	} while ( --size );
-
-	return ( value_i >= reference_i );
-}
-
-/**
- * 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 uint64_t *value0, unsigned int size ) {
-	const uint64_t *value = ( value0 + size );
-	int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
-	uint64_t value_i;
-
-	do {
-		value_i = *(--value);
-		max_bit -= ( 64 - fls ( value_i ) );
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return max_bit;
-}
-
-/**
  * Grow big integer
  *
  * @v source0		Element 0 of source big integer
@@ -286,25 +193,6 @@
 }
 
 /**
- * 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 uint64_t *value0, unsigned int size __unused,
-		  void *out, size_t len ) {
-	const uint8_t *value_byte = ( ( const void * ) value0 );
-	uint8_t *out_byte = ( out + len );
-
-	/* Copy raw data in reverse order */
-	while ( len-- )
-		*(--out_byte) = *(value_byte++);
-}
-
-/**
  * Multiply big integer elements
  *
  * @v multiplicand	Multiplicand element
diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h
index ac475da..b2938f8 100644
--- a/src/arch/loong64/include/bits/bigint.h
+++ b/src/arch/loong64/include/bits/bigint.h
@@ -11,34 +11,11 @@
 
 #include <stdint.h>
 #include <string.h>
-#include <strings.h>
 
 /** Element of a big integer */
 typedef uint64_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 ( uint64_t *value0, unsigned int size,
-		  const void *data, size_t len ) {
-	size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
-	uint8_t *value_byte = ( ( void * ) value0 );
-	const uint8_t *data_byte = ( data + len );
-
-	/* Copy raw data in reverse order, padding with zeros */
-	while ( len-- )
-		*(value_byte++) = *(--data_byte);
-	while ( pad_len-- )
-		*(value_byte++) = 0;
-}
-
-/**
  * Add big integers
  *
  * @v addend0		Element 0 of big integer to add
@@ -227,76 +204,6 @@
 }
 
 /**
- * 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 uint64_t *value0, unsigned int size ) {
-	const uint64_t *value = value0;
-	uint64_t value_i;
-
-	do {
-		value_i = *(value++);
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return ( value_i == 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
- */
-static inline __attribute__ (( always_inline, pure )) int
-bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0,
-		    unsigned int size ) {
-	const uint64_t *value = ( value0 + size );
-	const uint64_t *reference = ( reference0 + size );
-	uint64_t value_i;
-	uint64_t reference_i;
-
-	do {
-		value_i = *(--value);
-		reference_i = *(--reference);
-		if ( value_i != reference_i )
-			break;
-	} while ( --size );
-
-	return ( value_i >= reference_i );
-}
-
-/**
- * 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 uint64_t *value0, unsigned int size ) {
-	const uint64_t *value = ( value0 + size );
-	int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
-	uint64_t value_i;
-
-	do {
-		value_i = *(--value);
-		max_bit -= ( 64 - fls ( value_i ) );
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return max_bit;
-}
-
-/**
  * Grow big integer
  *
  * @v source0		Element 0 of source big integer
@@ -329,25 +236,6 @@
 }
 
 /**
- * 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 uint64_t *value0, unsigned int size __unused,
-		  void *out, size_t len ) {
-	const uint8_t *value_byte = ( ( const void * ) value0 );
-	uint8_t *out_byte = ( out + len );
-
-	/* Copy raw data in reverse order */
-	while ( len-- )
-		*(--out_byte) = *(value_byte++);
-}
-
-/**
  * Multiply big integer elements
  *
  * @v multiplicand	Multiplicand element
diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h
index 89718f3..70a267b 100644
--- a/src/arch/riscv/include/bits/bigint.h
+++ b/src/arch/riscv/include/bits/bigint.h
@@ -11,34 +11,11 @@
 
 #include <stdint.h>
 #include <string.h>
-#include <strings.h>
 
 /** Element of a big integer */
 typedef unsigned long 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 ( unsigned long *value0, unsigned int size,
-		  const void *data, size_t len ) {
-	size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len );
-	uint8_t *value_byte = ( ( void * ) value0 );
-	const uint8_t *data_byte = ( data + len );
-
-	/* Copy raw data in reverse order, padding with zeros */
-	while ( len-- )
-		*(value_byte++) = *(--data_byte);
-	while ( pad_len-- )
-		*(value_byte++) = 0;
-}
-
-/**
  * Add big integers
  *
  * @v addend0		Element 0 of big integer to add
@@ -222,76 +199,6 @@
 }
 
 /**
- * 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 unsigned long *value0, unsigned int size ) {
-	const unsigned long *value = value0;
-	unsigned long value_i;
-
-	do {
-		value_i = *(value++);
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return ( value_i == 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
- */
-static inline __attribute__ (( always_inline, pure )) int
-bigint_is_geq_raw ( const unsigned long *value0,
-		    const unsigned long *reference0, unsigned int size ) {
-	const unsigned long *value = ( value0 + size );
-	const unsigned long *reference = ( reference0 + size );
-	unsigned long value_i;
-	unsigned long reference_i;
-
-	do {
-		value_i = *(--value);
-		reference_i = *(--reference);
-		if ( value_i != reference_i )
-			break;
-	} while ( --size );
-
-	return ( value_i >= reference_i );
-}
-
-/**
- * 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 unsigned long *value0, unsigned int size ) {
-	const unsigned long *value = ( value0 + size );
-	int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) );
-	unsigned long value_i;
-
-	do {
-		value_i = *(--value);
-		max_bit -= ( ( 8 * sizeof ( *value0 ) ) - fls ( value_i ) );
-		if ( value_i )
-			break;
-	} while ( --size );
-
-	return max_bit;
-}
-
-/**
  * Grow big integer
  *
  * @v source0		Element 0 of source big integer
@@ -325,25 +232,6 @@
 }
 
 /**
- * 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 unsigned long *value0, unsigned int size __unused,
-		  void *out, size_t len ) {
-	const uint8_t *value_byte = ( ( const void * ) value0 );
-	uint8_t *out_byte = ( out + len );
-
-	/* Copy raw data in reverse order */
-	while ( len-- )
-		*(--out_byte) = *(value_byte++);
-}
-
-/**
  * Multiply big integer elements
  *
  * @v multiplicand	Multiplicand element
diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h
index 21cffa0..e4ac52d 100644
--- a/src/arch/x86/include/bits/bigint.h
+++ b/src/arch/x86/include/bits/bigint.h
@@ -10,46 +10,11 @@
 FILE_SECBOOT ( PERMITTED );
 
 #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 ) {
-	bigint_t ( size ) __attribute__ (( may_alias )) *value =
-		( ( void * ) value0 );
-	long pad_len = ( sizeof ( *value ) - len );
-	void *discard_D;
-	long discard_c;
-
-	/* Copy raw data in reverse order, padding with zeros */
-	__asm__ __volatile__ ( "jecxz 2f\n\t"
-			       "\n1:\n\t"
-			       "movb -1(%3,%1), %%al\n\t"
-			       "stosb\n\t"
-			       "loop 1b\n\t"
-			       "\n2:\n\t"
-			       "xorl %%eax, %%eax\n\t"
-			       "mov %4, %1\n\t"
-			       "rep stosb\n\t"
-			       : "=&D" ( discard_D ), "=&c" ( discard_c ),
-				 "+m" ( *value )
-			       : "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
-				 "1" ( len )
-			       : "eax" );
-}
-
-/**
  * Add big integers
  *
  * @v addend0		Element 0 of big integer to add
@@ -165,81 +130,6 @@
 }
 
 /**
- * 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 ) {
-	long discard_c;
-	long discard_tmp;
-	int result;
-
-	__asm__ __volatile__ ( "\n1:\n\t"
-			       "movl -4(%3, %1, 4), %k2\n\t"
-			       "cmpl -4(%4, %1, 4), %k2\n\t"
-			       "loope 1b\n\t"
-			       "setae %b0\n\t"
-			       : "=q" ( result ), "=&c" ( discard_c ),
-				 "=&r" ( discard_tmp )
-			       : "r" ( value0 ), "r" ( reference0 ),
-				 "0" ( 0 ), "1" ( size ) );
-	return result;
-}
-
-/**
- * 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
@@ -294,36 +184,6 @@
 }
 
 /**
- * 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 ) {
-	struct {
-		uint8_t bytes[len];
-	} __attribute__ (( may_alias )) *out_bytes = out;
-	void *discard_D;
-	long discard_c;
-
-	/* Copy raw data in reverse order */
-	__asm__ __volatile__ ( "jecxz 2f\n\t"
-			       "\n1:\n\t"
-			       "movb -1(%3,%1), %%al\n\t"
-			       "stosb\n\t"
-			       "loop 1b\n\t"
-			       "\n2:\n\t"
-			       : "=&D" ( discard_D ), "=&c" ( discard_c ),
-				 "+m" ( *out_bytes )
-			       : "r" ( value0 ), "0" ( out ), "1" ( len )
-			       : "eax" );
-}
-
-/**
  * Multiply big integer elements
  *
  * @v multiplicand	Multiplicand element
diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c
index 5d2f7b5..d3eafe1 100644
--- a/src/crypto/bigint.c
+++ b/src/crypto/bigint.c
@@ -26,7 +26,9 @@
 
 #include <stdint.h>
 #include <string.h>
+#include <strings.h>
 #include <assert.h>
+#include <byteswap.h>
 #include <stdio.h>
 #include <ipxe/bigint.h>
 
@@ -82,6 +84,138 @@
 }
 
 /**
+ * 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
diff --git a/src/crypto/ffdhe.c b/src/crypto/ffdhe.c
index 7dc9457..41bd908 100644
--- a/src/crypto/ffdhe.c
+++ b/src/crypto/ffdhe.c
@@ -42,6 +42,7 @@
  */
 
 #include <stdint.h>
+#include <string.h>
 #include <errno.h>
 #include <ipxe/ffdhe.h>
 
diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c
index 783e07a..ab2df24 100644
--- a/src/crypto/weierstrass.c
+++ b/src/crypto/weierstrass.c
@@ -45,6 +45,7 @@
  * implementation of the big integer operations.
  */
 
+#include <string.h>
 #include <errno.h>
 #include <ipxe/weierstrass.h>