From e965c31ec4942ead78af8ebccd8fd2528e649c18 Mon Sep 17 00:00:00 2001 From: John Regan Date: Sun, 2 Apr 2023 16:17:57 -0400 Subject: [PATCH] add functions to convert to standard types --- bigint.h | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++ utest.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) diff --git a/bigint.h b/bigint.h index cc74b78..6fb03d8 100644 --- a/bigint.h +++ b/bigint.h @@ -143,6 +143,57 @@ int bigint_from_string(bigint* b, const char* str, size_t len, unsigned int base BIGINT_API int bigint_from_cstring(bigint* b, const char* str, unsigned int base); +BIGINT_API +int bigint_from_u8(bigint* b, uint8_t val); + +BIGINT_API +int bigint_from_i8(bigint* b, int8_t val); + +BIGINT_API +int bigint_from_u16(bigint* b, uint16_t val); + +BIGINT_API +int bigint_from_i16(bigint* b, int16_t val); + +BIGINT_API +int bigint_from_u32(bigint* b, uint32_t val); + +BIGINT_API +int bigint_from_i32(bigint* b, int32_t val); + +BIGINT_API +int bigint_from_u64(bigint* b, uint64_t val); + +BIGINT_API +int bigint_from_i64(bigint* b, int64_t val); + +/* bigint_to functions return 0 on success, 1 if the + * bigint won't fit into the type */ + +BIGINT_API +int bigint_to_u8(uint8_t *val, const bigint* b); + +BIGINT_API +int bigint_to_i8(int8_t *val, const bigint* b); + +BIGINT_API +int bigint_to_u16(uint16_t * val, const bigint* b); + +BIGINT_API +int bigint_to_i16(int16_t * val, const bigint* b); + +BIGINT_API +int bigint_to_u32(uint32_t * val, const bigint* b); + +BIGINT_API +int bigint_to_i32(int32_t * val, const bigint* b); + +BIGINT_API +int bigint_to_u64(uint64_t * val, const bigint* b); + +BIGINT_API +int bigint_to_i64(int64_t * val, const bigint* b); + BIGINT_API size_t bigint_to_string(char* str, size_t len, const bigint* b, unsigned int base); @@ -186,6 +237,7 @@ int bigint_rshift_overwrite(bigint* a, size_t bits); BIGINT_API void bigint_div_mod_word(bigint* numerator, bigint_word* remainder, bigint_word denominator); + #ifdef __cplusplus } #endif @@ -1121,12 +1173,14 @@ int bigint_copy(bigint *dest, const bigint *src) { BIGINT_API int bigint_from_word(bigint* b, bigint_word val) { bigint_reset(b); + if(!val) return 0; return bigint_append(b,val); } BIGINT_API int bigint_from_u8(bigint* b, uint8_t val) { bigint_reset(b); + if(!val) return 0; return bigint_append(b, (bigint_word)(val & BIGINT_WORD_MASK) ); } @@ -1134,6 +1188,7 @@ BIGINT_API int bigint_from_u16(bigint* b, uint16_t val) { int r; bigint_reset(b); + if(!val) return 0; #if BIGINT_WORD_WIDTH < 2 while(val) { r = bigint_append(b, (bigint_word)(val & BIGINT_WORD_MASK)); @@ -1150,6 +1205,7 @@ BIGINT_API int bigint_from_u32(bigint* b, uint32_t val) { int r; bigint_reset(b); + if(!val) return 0; #if BIGINT_WORD_WIDTH < 4 while(val) { r = bigint_append(b, (bigint_word)(val & BIGINT_WORD_MASK)); @@ -1166,6 +1222,7 @@ BIGINT_API int bigint_from_u64(bigint* b, uint64_t val) { int r; bigint_reset(b); + if(!val) return 0; #if BIGINT_WORD_WIDTH < 8 while(val) { r = bigint_append(b, (bigint_word)(val & BIGINT_WORD_MASK)); @@ -1222,6 +1279,127 @@ int bigint_from_i64(bigint* b, int64_t val) { return 0; } +static inline +uint64_t bigint_to_u64_internal(const bigint* b) { + uint64_t tmp = 0; + size_t i = b->size; + +#if BIGINT_WORD_WIDTH == 8 + if(i) tmp = b->words[0]; +#else + while(i--) { + tmp <<= BIGINT_WORD_BIT; + tmp += b->words[i] & BIGINT_WORD_MASK; + } +#endif + + return tmp; +} + +BIGINT_API +int bigint_to_u8(uint8_t *val, const bigint* b) { + uint64_t tmp = 0; + + if(bigint_bitlength(b) > 8) return 1; + if(b->size) { + tmp = bigint_to_u64_internal(b); + } + *val = (uint8_t)tmp; + return 0; +} + +BIGINT_API +int bigint_to_i8(int8_t *val, const bigint* b) { + uint8_t tmp = 0; + uint8_t max = INT8_MAX; + int r = 0; + + if( (r = bigint_to_u8(&tmp,b)) != 0) return r; + max += !!b->sign; + if(tmp > max) return 1; + + *val = b->sign ? -tmp : tmp; + return 0; +} + +BIGINT_API +int bigint_to_u16(uint16_t *val, const bigint* b) { + uint64_t tmp = 0; + + if(bigint_bitlength(b) > 16) return 1; + if(b->size) { + tmp = bigint_to_u64_internal(b); + } + *val = (uint16_t)tmp; + return 0; +} + +BIGINT_API +int bigint_to_i16(int16_t *val, const bigint* b) { + uint16_t tmp = 0; + uint16_t max = INT16_MAX; + int r = 0; + + if( (r = bigint_to_u16(&tmp,b)) != 0) return r; + max += !!b->sign; + if(tmp > max) return 1; + + *val = b->sign ? -tmp : tmp; + return 0; +} + +BIGINT_API +int bigint_to_u32(uint32_t *val, const bigint* b) { + uint64_t tmp = 0; + + if(bigint_bitlength(b) > 32) return 1; + if(b->size) { + tmp = bigint_to_u64_internal(b); + } + *val = (uint32_t)tmp; + return 0; +} + +BIGINT_API +int bigint_to_i32(int32_t *val, const bigint* b) { + uint32_t tmp = 0; + uint32_t max = INT32_MAX; + int r = 0; + + if( (r = bigint_to_u32(&tmp,b)) != 0) return r; + max += !!b->sign; + if(tmp > max) return 1; + + *val = b->sign ? -tmp : tmp; + return 0; +} + +BIGINT_API +int bigint_to_u64(uint64_t *val, const bigint* b) { + uint64_t tmp = 0; + + if(bigint_bitlength(b) > 64) return 1; + if(b->size) { + tmp = bigint_to_u64_internal(b); + } + *val = (uint64_t)tmp; + return 0; +} + +BIGINT_API +int bigint_to_i64(int64_t *val, const bigint* b) { + uint64_t tmp = 0; + uint64_t max = INT64_MAX; + int r = 0; + + if( (r = bigint_to_u64(&tmp,b)) != 0) return r; + max += !!b->sign; + if(tmp > max) return 1; + + *val = b->sign ? -tmp : tmp; + return 0; +} + static int bigint_add_signed(bigint* c, const bigint* a, size_t a_sign, const bigint* b, size_t b_sign) { int r; diff --git a/utest.c b/utest.c index 942c1f9..f75262b 100644 --- a/utest.c +++ b/utest.c @@ -2505,6 +2505,17 @@ UTEST(bigint,from_int16) { ASSERT_WEQ(a.words[0],0x8000); #endif + ASSERT_EQ(bigint_from_i16(&a,INT16_MAX),0); + ASSERT_EQ(a.sign,(size_t)0); +#if BIGINT_WORD_WIDTH == 1 + ASSERT_WEQ(a.size,2); + ASSERT_WEQ(a.words[0],0xFF); + ASSERT_WEQ(a.words[1],0x7F); +#else + ASSERT_WEQ(a.size,1); + ASSERT_WEQ(a.words[0],0x7FFF); +#endif + bigint_free(&a); } @@ -2643,4 +2654,184 @@ UTEST(bigint,cmp) { CLEANUP } +UTEST(bigint,to_uint8) { + PREAMBLE; + + uint8_t val = 255; + + ASSERT_EQ(bigint_from_u8(&a,0),0); + ASSERT_EQ(bigint_to_u8(&val,&a),0); + ASSERT_EQ(val,0); + + ASSERT_EQ(bigint_from_u8(&a,255),0); + ASSERT_EQ(bigint_to_u8(&val,&a),0); + ASSERT_EQ(val,255); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_u8(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_int8) { + PREAMBLE; + + int8_t val = 0x7F; + + ASSERT_EQ(bigint_from_u8(&a,0),0); + ASSERT_EQ(bigint_to_i8(&val,&a),0); + ASSERT_EQ(val,0); + + ASSERT_EQ(bigint_from_u8(&a,0x7F),0); + ASSERT_EQ(bigint_to_i8(&val,&a),0); + ASSERT_EQ(val,0x7F); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_i8(&val,&a),1); + + a.sign = 1; + ASSERT_EQ(bigint_to_i8(&val,&a),0); + ASSERT_EQ(val,-0x80); + + ASSERT_EQ(bigint_dec(&a,&a),0); + ASSERT_EQ(bigint_to_i8(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_uint16) { + PREAMBLE; + + uint16_t val = UINT16_MAX; + + ASSERT_EQ(bigint_from_u16(&a,0),0); + ASSERT_EQ(bigint_to_u16(&val,&a),0); + ASSERT_EQ(val,0); + + ASSERT_EQ(bigint_from_u16(&a,UINT16_MAX),0); + ASSERT_EQ(bigint_to_u16(&val,&a),0); + ASSERT_EQ(val,UINT16_MAX); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_u16(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_int16) { + PREAMBLE; + + int16_t val = INT16_MAX; + + ASSERT_EQ(bigint_from_u16(&a,0),0); + ASSERT_EQ(bigint_to_i16(&val,&a),0); + ASSERT_EQ(val,0); + + ASSERT_EQ(bigint_from_u16(&a,INT16_MAX),0); + ASSERT_EQ(bigint_to_i16(&val,&a),0); + ASSERT_EQ(val,INT16_MAX); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_i16(&val,&a),1); + + a.sign = 1; + ASSERT_EQ(bigint_to_i16(&val,&a),0); + ASSERT_EQ(val,INT16_MIN); + + ASSERT_EQ(bigint_dec(&a,&a),0); + ASSERT_EQ(bigint_to_i16(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_uint32) { + PREAMBLE; + + uint32_t val = UINT32_MAX; + + ASSERT_EQ(bigint_from_u32(&a,0),0); + ASSERT_EQ(bigint_to_u32(&val,&a),0); + ASSERT_WEQ(val,0); + + ASSERT_EQ(bigint_from_u32(&a,UINT32_MAX),0); + ASSERT_EQ(bigint_to_u32(&val,&a),0); + ASSERT_EQ(val,UINT32_MAX); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_u32(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_int32) { + PREAMBLE; + + int32_t val = INT32_MAX; + + ASSERT_EQ(bigint_from_u32(&a,0),0); + ASSERT_EQ(bigint_to_i32(&val,&a),0); + ASSERT_EQ(val,0); + + ASSERT_EQ(bigint_from_u32(&a,INT32_MAX),0); + ASSERT_EQ(bigint_to_i32(&val,&a),0); + ASSERT_EQ(val,INT32_MAX); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_i32(&val,&a),1); + + a.sign = 1; + ASSERT_EQ(bigint_to_i32(&val,&a),0); + ASSERT_EQ(val,INT32_MIN); + + ASSERT_EQ(bigint_dec(&a,&a),0); + ASSERT_EQ(bigint_to_i32(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_uint64) { + PREAMBLE; + + uint64_t val = UINT64_MAX; + + ASSERT_EQ(bigint_from_u64(&a,0),0); + ASSERT_EQ(bigint_to_u64(&val,&a),0); + ASSERT_WEQ(val,0); + + ASSERT_EQ(bigint_from_u64(&a,UINT64_MAX),0); + ASSERT_EQ(bigint_to_u64(&val,&a),0); + ASSERT_EQ(val,UINT64_MAX); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_u64(&val,&a),1); + + CLEANUP; +} + +UTEST(bigint,to_int64) { + PREAMBLE; + + int64_t val = INT64_MAX; + + ASSERT_EQ(bigint_from_u64(&a,0),0); + ASSERT_EQ(bigint_to_i64(&val,&a),0); + ASSERT_EQ(val,0); + + ASSERT_EQ(bigint_from_u64(&a,INT64_MAX),0); + ASSERT_EQ(bigint_to_i64(&val,&a),0); + ASSERT_EQ(val,INT64_MAX); + + ASSERT_EQ(bigint_inc(&a,&a),0); + ASSERT_EQ(bigint_to_i64(&val,&a),1); + + a.sign = 1; + ASSERT_EQ(bigint_to_i64(&val,&a),0); + ASSERT_EQ(val,INT64_MIN); + + ASSERT_EQ(bigint_dec(&a,&a),0); + ASSERT_EQ(bigint_to_i64(&val,&a),1); + + CLEANUP; +} + UTEST_MAIN();