반응형
이 글에서 다루고 있는 메인 주제인 큰 수에 대한 연산 및 암호화 연산에서 사용되는 대표적인 도우미 함수들에 대해서 설명한다.
일반적인 도우미함수들은 doumi.h에 정의하고 doumi.c에 구현할 것이다. 이 때, 함수명은 표준 C라이브러리에서 사용되는 함수들과의 혼돈을 피하기 위해서 "do_"로 시작되도록 한다.
BIGINT관련 도우미함수들은 bigint.c내에 구현한다.
1. 일반 도우미 함수들 (doumi.h에 정의. doumi.c에 구현)
do_compare
/************************************************************************** compare two bytes(=unsigned char *) value Input: @a, @b 비교하려는 두 수에 대한 포인터변수 a, b @len 비교하려는 길이 Returns: 1 : a > b 0 : a==b -1: a < b ***************************************************************************/ int do_compare(unsigned char *a, unsigned char *b, unsigned short len){ unsigned char *posA, *posB; if(len == 0) return 0; posA = a + len; posB = b + len; while( (*posA == *posB) && (posA > a)){ posA--; posB--; } if(posA == a) return 0; if(*posA > *posB) return 1; else return -1; }
do_power
/************************************************************************** int값에 대한 지수승값 구한다. Input: @base 밑 수 @e 지수 Returns: power(base,e)의 결과값. long타입 ***************************************************************************/ unsigned long do_power(int base, int e){ unsigned long result = 1; while(e--){ result *= base; } return result; }
do_len
/************************************************************************** 주어진 문자열의 크기를 구한다. 즉, char형 갯수 만약, 문자열의 길이가 int변수가 나타낼 수 있는 크기보다 크다면 -1리턴 Input: @s 길이를 알아내려는 문자열 포인터 Returns: 문자열 s의 길이. 만약 int형으로 표현되는 Max보다 크다면 -1리턴 ***************************************************************************/ int do_len(char *s){ unsigned int len=0; unsigned int max = do_power(2,(sizeof(int) * 8 - 1)); while(*s++ != '\0') { len++; if(len >= max) return -1; } return len; }
do_tolower
/************************************************************************** 주어진 알파벳 문자에 해당하는 대문자 리턴. 주어진 것이 이미 대문자이면 그냥 그 대문자 리턴 Input: @c 입력 문자 Returns: 입력문자에 해당하는 대문자 ***************************************************************************/ int do_tolower(int c){ if( (c >= 'A') && (c <= 'Z')) return (c - 'A' + 'a'); else return c; }
do_hex2num
/************************************************************************** hexa형태의 문자를 숫자로 변환 '1' -> 1, 'a' -> 10, 'A'->10, Input: @c hexa형태의 문자 Returns: '0'~'9' : 0 ~ 9 'a'~'f' : 10 ~ 15 'A' ~ 'F': 10 ~ 15 그 외: -1 ***************************************************************************/ int do_hex2num(int c){ if( (c >= 'A') && (c <= 'F')) return (c - 'A' + 10); else if( (c >= 'a') && (c <= 'f')) return (c - 'a' + 10); else if( (c >= '0') && (c <= '9')) return (c - '0'); else return -1; }
do_int2hexchar
/************************************************************************** 숫자를 hexa형태의 문자로 변환 1 -> '1' , 10 -> 'A' Input: @i hexa형태의 문자로 변환하려는 숫자 Returns: 0 ~ 9: '0'~'9' 10 ~ 15: 'A'~'F' : 그 외: -1 ***************************************************************************/ char do_int2hexchar(int i){ if(i<0 || i >= 16) return -1; if(i < 10) return (char)(i + (int)'0'); return (char)(i - 10 + (int)'A'); }
do_reverse
/************************************************************************** 문자열의 차례를 뒤 바꿈 "abcd" -> "dcba" Input: @s 바꾸려는 문자열. 순서가 바뀌어서 다시 입력 문자열에 저장됨 Returns: 0 성공 -1 에러 ***************************************************************************/ int do_reverse(char* s){ int i; char t; int len = do_len(s); if(len < 0) return -1; for(i=0;i<(len/2);++i){ t = s[i]; s[i] = s[len - i]; s[len - i] = t; } return 0; }
do_copy
/************************************************************************** short형 두 배열에 대해, 한 쪽 배열값을 다른 쪽 배열에 카피 Input: @tgt Target 포인터 @tgtStart Paste하려는 Target포인터의 첫번째 위치. 만약 2라면. tgt[2]에다 paset. 첨자 시작은 0 @src Source 포인터 @srcStart Copy시작하는 src배열의 위치. 만약 2라면 src[2]부터 copy @len copy할 길이. src[srcStart]부터 len길이만큼 copy해서, tgt[tgtStart]에 paste ***************************************************************************/ void do_copy(unsigned char *tgt, unsigned short tgtStart, unsigned char *src, unsigned short srcStart, unsigned short len){ int i=0; tgt += tgtStart; src += srcStart; while(len-- > 0) *(tgt++) = *(src++); }
doumi.h에 정의된 함수들
int do_compare(unsigned char *a, unsigned char *b, unsigned short len); unsigned long do_power(int , int ); int do_len(char*); int do_hex2num(int); char do_int2hexchar(int); int do_reverse(char*); void do_copy(unsigned char *tgt, unsigned short tgtStart, unsigned char *src, unsigned short srcStart, unsigned short len);
2. BIGINT관련 도우미 함수들 (bigint.c에 정의)
compare_big
/************************************************************************** compare two BIGINT value 음수에 대한 고려하지 않음. 즉, 양수인 BIGINT값에 대해서만 유의한 결과를 보임 Input: @a, @b Returns: 1 : a > b 0 : a==b -1: a < b ***************************************************************************/ int compare_big(BIGINT a, BIGINT b){ int lenA, lenB; INT *posA, *posB;//1. check len is not zero lenA = (int)*a; lenB = (int)*b; if(lenA == 0 && lenB == 0) return 0;
//2. check non zero value len and compare length while(a[lenA]==0 && lenA>0) --lenA; while(b[lenB]==0 && lenB>0) --lenB; if(lenA == 0 && lenB == 0) return 0; if(lenA > lenB) return 1; if(lenA < lenB) return -1;
//3. case:lenA == lenB posA = a + lenA; posB = b + lenB; while( (*posA == *posB) && (posA > a)){ posA--; posB--; } if(posA == a) return 0; if(*posA > *posB) return 1; else return -1; }
increse
/************************************************************************** 1을 더함 Input: @A Output: (A+1) A에 1을 더한 값. A = A + 1 Returns: OK : no error E_Overflow: Overflow. if larger than MAX_INT_LEN(=128. in case of INT is u32) ***************************************************************************/ int increse(BIGINT A){ INT *a, *ae; DINT carry = BASE; //01. A에 대한 포인터얻기 a = A + 1; ae = A + SIZE(A); //02. if(A == zero) if(a > ae){ SET_SIZE(A,1); *a = (INT)1; return OK; } //03. loop while((a <= ae) && (carry & BASE)){ *a = (INT)(carry = (DINT)*a + (DINT)1); a++; } //04. if carry exist --> increse len if((a > ae) && (carry & BASE)){ if( (SIZE(A)+1) > MAX_INT_LEN){ *A = 0; //set zero }else{ *a = 1; SET_SIZE(A, (SIZE(A))+1); } } //05. if(A == 양의 최대값) -> +1이면 overflow if((SIZE(A) == MAX_INT_LEN) && (A[MAX_INT_LEN] == ((INT)MAX_POSITIVE+1))){ ae = A+SIZE(A); while((*ae == 0) && (--ae > A)); //모두 zero라면 if(ae == A) return E_Overflow; } return OK; }
negative
/*************************************************************************************** 주어진 BIGINT값을 음수로 변환 이 때 음수의 표현은 2의 보수 형태 즉, 00101 -> 11010 -> 11011 input: BIGINT A 음수로 변환할 BIGINT값 output: BIGINT A 2의보수 형태로 변환된 값 return: OK ****************************************************************************************/ int negative(BIGINT A){ INT *a = A; INT *ae = A + SIZE(A); //1. if zero --> do nothing if(*(a+1) == 0) return OK; //2. 1's complement while(++a <= ae){ *a = ~(*a); } //1. +1 //앞에서 zero인 경우에 대해서 처리했기에, 1의 보수에 의해 MAX된 후, //increse에 의해 overflow가 발생되는 경우 없음 increse(A); //2. fill with FF upto the MAX SET_SIZE(A,MAX_INT_LEN); while(++ae <= (A+MAX_INT_LEN)){ *ae = MAX_INT; } return OK; }
hexstr2bigint
/**************************************************************************
convert hex string to BIGINT
음수부호가 있는 hexa string값은 처리하지 않음.
음수부호가 있을 경우는 hexstr2bigint함수 사용해야함
Input: @str: should be big endian style notation.
ex)ff12 = f x 4096 + f x 256 + 1 x 16 + 2
1234567890 ==> [0]2 [1]12 [2]34567890
= 0x12 x B^0 + 0x34567890 x B^1
Output: @a: converted BIGINT value
ex)"112233445566" -> {2, 0x00005566, 0x11223344}
Returns:
OK : no error
E_NotSupported: not supported. possible BIGINT type is u8, u16, u32
***************************************************************************/
int hexstr2bigint_engine(char* str, BIGINT a){
int sizeofINT= sizeof(INT), result=OK;
int strLen;
int i,j,len,n;
INT t;
unsigned long strStart;
unsigned short byteLen, bigIntLen;
//1. 초기값 세팅
*a = 0;
strLen = do_len(str);
if(strLen < 0) return E_Overflow;
strStart = (unsigned long)str;
byteLen = strLen / 2;
bigIntLen = ((byteLen % sizeofINT)==0) ? byteLen/sizeofINT : (byteLen/sizeofINT)+1;
if(bigIntLen > MAX_INT_LEN) return E_Overflow;
//2. loop
str = str + strLen-1;
for(i=1;i <= bigIntLen ;i++){
t=0;
len = (((unsigned long)str - strStart+1) > (unsigned long)(sizeofINT * 2)) ? (int)(sizeofINT * 2) : (int)((unsigned long)str - strStart+1);
for(j=0;j<len;j++){
n = do_hex2num(*(str - j));
if(n<0) return E_WrongFormat;
t += (INT)(n * do_power(16,j));
}
*(a+i) = t;
str -= (sizeofINT * 2);
}
*a = bigIntLen;
return result;
}
/**************************************************************************
convert string to BIGINT
입력값으로 부호(+ 혹은 -) 붙여서 변환 시킬 수 있음
case 1)부호없는 hexa string: "112233445566" -> {2, 0x00005566, 0x11223344}
case 2)양수 부호 있는 hexa string = 부호없는 hexa string
case 3)음수 부호 있는 hexa string:
"-112233445566" -> {0x80,0xFFFFAA9A, 0xEEDDCCBB, 0xFFFFFFFF, ..., 0xFFFFFFFF}
Input: @str: should be big endian style notation.
ex)ff12 = f x 4096 + f x 256 + 1 x 16 + 2
1234567890 ==> [0]2 [1]12 [2]34567890
= 0x12 x B^0 + 0x34567890 x B^1
Output: @a: converted BIGINT value
ex1)"112233445566" -> {2, 0x00005566, 0x11223344}
ex2)"-112233445566" -> {0x80,0xFFFFAA9A, 0xEEDDCCBB, 0xFFFFFFFF, ..., 0xFFFFFFFF}
Returns:
OK : no error
E_NotSupported: not supported. possible BIGINT type is u8, u16, u32
***************************************************************************/
int hexstr2bigint(char* str, BIGINT a){
char *strNum;
int ret=-1;
//음수 부호가 있는 지 확인
if(*str == '-'){
strNum = (str + 1);
ret = hexstr2bigint_engine(strNum, a);
if(ret != OK) return ret;
else{
return negative(a);
}
}else if(*str == '+'){
strNum = (str + 1);
return hexstr2bigint_engine(strNum, a);
}else{
return hexstr2bigint_engine(str, a);
}
}
hexstr2bytes
/************************************************************************** convert string to bytes Input: @str: should be big endian style notation. ex)ff12 = f x 4096 + f x 256 + 1 x 16 + 2 1234567890 ==> [0]2 [1]12 [2]34567890 = 0x12 x B^0 + 0x34567890 x B^1 Output: @a: converted bytes(unsigned char*) value "112233445566" -> {0x11223344, 0x5566} Returns: OK : no error E_WrongFormat: if str contains wrong character. should be between 0~9, a~f, A~F ***************************************************************************/ int hexstr2bytes(char* str, unsigned char* a){ int strLen,bytesLen; int i,n; unsigned char c; strLen = do_len(str); bytesLen = strLen / 2; for(i=0;i < bytesLen ;i++){ n = do_hex2num(*str); if(n<0) return E_WrongFormat; c = n * 16; n = s_hex2num(*(str+1)); if(n<0) return E_WrongFormat; c += n; *(a+i) = c; str += 2; } //*(a+bytesLen) = '\0'; return 0; }
bytes2bigint
/************************************************************************** convert unsigned char to BIGINT Input: @c: unsigned char pointer @len: length of bytes of c Output: @a: converted BIGINT value 0x11 0x22 0x33 0x44 0x55 0x66 -> {2, 0x00005566, 0x11223344} Returns: OK : no error E_NotSupported: not supported. possible BIGINT type is u8, u16, u32 ***************************************************************************/ int bytes2bigint(unsigned char* c, unsigned short bytesLen, BIGINT a){ int sizeofINT= sizeof(INT), result=OK; int i,j,n,len; INT t; unsigned long cStart; unsigned short bigIntLen; //1. 초기값 세팅 *a = 0; if(bytesLen < 0) return E_Underflow; cStart = (unsigned long)c; bigIntLen = ((bytesLen % sizeofINT)==0) ? bytesLen/sizeofINT : (bytesLen/sizeofINT)+1; if(bigIntLen > MAX_INT_LEN) return E_Overflow; //2. loop //str = str + strLen-1; c = c + bytesLen-1; for(i=1;i <= bigIntLen ;i++){ t=0; len = (((unsigned long)c - cStart+1) > (unsigned long)sizeofINT) ? (int)sizeofINT : (int)((unsigned long)c - cStart+1); for(j=0;j<len;j++){ n = *(c-j); t += (INT)(n * do_power(256,j)); } *(a+i) = t; c -= sizeofINT; } *a = bigIntLen; return result; }
bigint2hexstr
/************************************************************************** convert BIGINT to hex string Input: @a: BIGINT value Returns : hex string of input BIGINT a a = {2, 0x00005566, 0x11223344} str = "112233445566" ***************************************************************************/ char* bigint2hexstr(BIGINT a){ int i,j,k; int sizeofINT= sizeof(INT), intBitLen, result=OK; unsigned short aLen = (unsigned short)(*a); static char s[MAX_BIT_LEN/4]; //error 처리 if(aLen == 0) { s[0] = '0'; s[1] = '\0'; return s; } //loop from the end of BIGINT a except a[1] intBitLen = sizeofINT * 8; k=0; for(i=aLen;i>=1;i--){ for(j=1;j<=(sizeofINT * 2);j++){ s[k++] = do_int2hexchar( (a[i] >> (intBitLen - 4 * j)) & 0x0f ); } } s[k] = '\0'; return s; }
bigint2bytes
/************************************************************************** convert BIGINT to bytes Input: @a: BIGINT value Returns : bytes value converted from BIGINT {2, 0x00005566, 0x11223344} -> 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 ***************************************************************************/ unsigned char * bigint2bytes(BIGINT a){ int i,j,k; int sizeofINT= sizeof(INT), intBitLen, result=OK; unsigned short aLen = (unsigned short)(*a); static unsigned char b[MAX_BIT_LEN/8]={0,}; //return zero if(aLen == 0) { return b; } //loop from the end of BIGINT a except a[1] intBitLen = sizeofINT * 8; k=0; for(i=aLen;i>=1;i--){ for(j=1;j<= sizeofINT;j++){ b[k++] = (a[i] >> (intBitLen-(8 * j))) & 0xff ; } } return b; }
copy_big
/************************************************************************** copy BIGINT Input: @tgt: Target BIGINT to be copy @src: Source BIGINT to copy Returns : void ***************************************************************************/ void copy_big(BIGINT tgt, BIGINT src){ int len = *src; if(len < 0 ) return; //do nothing while(len >= 0){ *tgt++ = *src++; len--; } }
setmax
/************************************************************************** 주어진 BIGINT를 max값으로 채움. 만약 INT가 4Bytes라면, 0xffffffff로 모든 BIGINT값이 채워짐 Input: @A: BIGINT to be filled with Max value Returns : void ***************************************************************************/ void setmax(BIGINT A){ INT *a = A; INT *ae = A + MAX_INT_LEN; while(++a <= ae){ *a = MAX_INT; //0xffffffff } SET_SIZE(A,MAX_INT_LEN); return; }
complement
/************************************************************************** 주어진 BIGINT의 비트값을 0이면 1로, 1이면 0으로 바꿈 Input: @A: BIGINT to convert all bits to complement bit Returns : void ***************************************************************************/ void complement(BIGINT A){ INT *a = A; INT *ae = A + SIZE(A); while(++a <= ae){ *a = ~(*a); } return; }
isPositive
/************************************************************************** 주어진 BIGINT가 양수인지 판별 Input: @A: BIGINT to determine whether it's positive or not Returns : 1 if BIGINT is positive value including zero -1 if BIGINT is negative value. ***************************************************************************/ int isPositive(BIGINT A){ if( (*A == MAX_INT_LEN) && (*(A+MAX_INT_LEN) > MAX_POSITIVE)) return -1; else return 1; }
* Add프로젝트에서는 에러코드로 OK와 E_Overflow만이 bigint.h에 정의되어 사용되었으나, 위 도우미 함수에서는 그 외에도 몇 개의 에러코드를 사용한다. 이 에러코드를 포함해서 bigint.h에 다음과 같이 에러코드를 추가 정의한다.
#define OK 0 #define E_Overflow -1 #define E_NotSupported -2 #define E_WrongFormat -3 #define E_ZeroLength -4 #define E_DivideByZero -5 #define E_Underflow -6
반응형
'암호화프로그래밍 > (Old)C-BIGINT(부록)' 카테고리의 다른 글
부록2. Visual Studio를 이용한 C 프로그래밍 예제 (0) | 2013.06.20 |
---|---|
부록1. 각 언어의 자료형별 크기 (0) | 2013.06.19 |