mirror of
https://github.com/ipxe/ipxe
synced 2025-12-22 21:11:03 +03:00
[crypto] Add big-integer library for RSA calculations
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>
This commit is contained in:
90
src/arch/x86/core/x86_bigint.c
Normal file
90
src/arch/x86/core/x86_bigint.c
Normal file
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
318
src/arch/x86/include/bits/bigint.h
Normal file
318
src/arch/x86/include/bits/bigint.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user