diff --git a/src/iota/bundle.c b/src/iota/bundle.c index aa2a1d44..64f11cb7 100644 --- a/src/iota/bundle.c +++ b/src/iota/bundle.c @@ -41,11 +41,11 @@ static void create_bundle_bytes(int64_t value, const char *tag, { trit_t bundle_essence_trits[243] = {0}; - int64_to_trits(value, bundle_essence_trits, 81); + s64_to_trits(value, bundle_essence_trits, 81); chars_to_trits(tag, bundle_essence_trits + 81, 27); - int64_to_trits(timestamp, bundle_essence_trits + 162, 27); - int64_to_trits(current_tx_index, bundle_essence_trits + 189, 27); - int64_to_trits(last_tx_index, bundle_essence_trits + 216, 27); + u32_to_trits(timestamp, bundle_essence_trits + 162, 27); + u32_to_trits(current_tx_index, bundle_essence_trits + 189, 27); + u32_to_trits(last_tx_index, bundle_essence_trits + 216, 27); // now we have exactly one chunk of 243 trits trits_to_bytes(bundle_essence_trits, bytes); diff --git a/src/iota/conversion.c b/src/iota/conversion.c index 69d7e883..4fcc25ef 100644 --- a/src/iota/conversion.c +++ b/src/iota/conversion.c @@ -2,108 +2,126 @@ #include #include "common.h" -#define INT_LENGTH 12 +#define UINT32_WIDTH 32 +#define NUM_TRYTE_VALUES (MAX_TRYTE_VALUE - MIN_TRYTE_VALUE + 1) + +// numer of u32 elements in one bigint array +#define BIGINT_LENGTH 12 + +// chunk sizes +#define NUM_CHUNK_TRYTES (NUM_HASH_TRYTES) +#define NUM_CHUNK_BYTES (NUM_HASH_BYTES) + // base of the ternary system #define BASE 3 +// base of the ternary system represented in bytes +#define TRYTE_BASE 27 + // the middle of the domain described by 242 trits, i.e. \sum_{k=0}^{241} 3^k -static const uint32_t HALF_3[12] = { +static const uint32_t HALF_3[BIGINT_LENGTH] = { 0xa5ce8964, 0x9f007669, 0x1484504f, 0x3ade00d9, 0x0c24486e, 0x50979d57, 0x79a4c702, 0x48bbae36, 0xa9f6808b, 0xaa06a805, 0xa87fabdf, 0x5e69ebef}; // the two's complement of HALF_3_u, i.e. ~HALF_3_u + 1 -static const uint32_t NEG_HALF_3[12] = { +static const uint32_t NEG_HALF_3[BIGINT_LENGTH] = { 0x5a31769c, 0x60ff8996, 0xeb7bafb0, 0xc521ff26, 0xf3dbb791, 0xaf6862a8, 0x865b38fd, 0xb74451c9, 0x56097f74, 0x55f957fa, 0x57805420, 0xa1961410}; -// representing the value of the highes trit in the feasible domain, i.e 3^242 -static const uint32_t TRIT_243[12] = { +// the value of the highest trit in the feasible domain, i.e 3^242 +static const uint32_t TRIT_243[BIGINT_LENGTH] = { 0x4b9d12c9, 0x3e00ecd3, 0x2908a09f, 0x75bc01b2, 0x184890dc, 0xa12f3aae, 0xf3498e04, 0x91775c6c, 0x53ed0116, 0x540d500b, 0x50ff57bf, 0xbcd3d7df}; -static const trit_t trits_mapping[27][3] = { +// the value of the highest trit in one tryte, i.e 3^3 +#define TRIT_4 9 + +// lookup table to convert a single tryte into the corresponding three trits +static const trit_t TRITS_TABLE[NUM_TRYTE_VALUES][3] = { {-1, -1, -1}, {0, -1, -1}, {1, -1, -1}, {-1, 0, -1}, {0, 0, -1}, {1, 0, -1}, {-1, 1, -1}, {0, 1, -1}, {1, 1, -1}, {-1, -1, 0}, {0, -1, 0}, {1, -1, 0}, {-1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {-1, 1, 0}, {0, 1, 0}, {1, 1, 0}, {-1, -1, 1}, {0, -1, 1}, {1, -1, 1}, {-1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {-1, 1, 1}, {0, 1, 1}, {1, 1, 1}}; -// available tryte chars in the correct order -static const char tryte_to_char_mapping[] = "NOPQRSTUVWXYZ9ABCDEFGHIJKLM"; +// lookup table to convert a single tryte into its char in base-27 encoding +static const char CHARS_TABLE[] = "NOPQRSTUVWXYZ9ABCDEFGHIJKLM"; -/* --------------------- trits > trytes and back */ -// used for bytes to chars and back -static int trytes_to_trits(const tryte_t trytes_in[], trit_t trits_out[], - unsigned int tryte_len) +static void trytes_to_trits(const tryte_t *trytes_in, trit_t *trits_out, + unsigned int trytes_len) { - for (unsigned int i = 0; i < tryte_len; i++) { - int8_t idx = (int8_t)trytes_in[i] + 13; - trits_out[i * 3 + 0] = trits_mapping[idx][0]; - trits_out[i * 3 + 1] = trits_mapping[idx][1]; - trits_out[i * 3 + 2] = trits_mapping[idx][2]; + for (unsigned int i = 0; i < trytes_len; i++) { + const unsigned int idx = *trytes_in++ - MIN_TRYTE_VALUE; + const trit_t *trits_mapping = TRITS_TABLE[idx]; + + *trits_out++ = trits_mapping[0]; + *trits_out++ = trits_mapping[1]; + *trits_out++ = trits_mapping[2]; } - return 0; } -static int trits_to_trytes(const trit_t trits_in[], tryte_t trytes_out[], - unsigned int trit_len) +static void trits_to_trytes(const trit_t *trits_in, tryte_t *trytes_out) { - for (unsigned int i = 0; i < trit_len / 3; i++) { - trytes_out[i] = trits_in[i * 3 + 0] + trits_in[i * 3 + 1] * 3 + - trits_in[i * 3 + 2] * 9; + for (unsigned int i = 0; i < NUM_CHUNK_TRYTES; i++) { + trytes_out[i] = *trits_in++; + trytes_out[i] += *trits_in++ * 3; + trytes_out[i] += *trits_in++ * 9; } - return 0; } -/* --------------------- END trits > trytes */ -/* --------------------- trytes > chars and back */ -// used for bytes to chars and back -int chars_to_trytes(const char chars_in[], tryte_t trytes_out[], - unsigned int len) +static void chars_to_trytes(const char *chars_in, tryte_t *trytes_out, + unsigned int chars_len) { - for (unsigned int i = 0; i < len; i++) { + for (unsigned int i = 0; i < chars_len; i++) { if (chars_in[i] == '9') { trytes_out[i] = 0; } - else if ((int8_t)chars_in[i] >= 'N') { - trytes_out[i] = (int8_t)(chars_in[i]) - 64 - 27; + else if (chars_in[i] >= 'N') { + trytes_out[i] = chars_in[i] - 'N' + MIN_TRYTE_VALUE; } else { - trytes_out[i] = (int8_t)(chars_in[i]) - 64; + trytes_out[i] = chars_in[i] - 'A' + 1; } } - return 0; } -static int trytes_to_chars(const tryte_t trytes_in[], char chars_out[], - unsigned int len) +static void trytes_to_chars(const tryte_t *trytes_in, char *chars_out, + unsigned int trytes_len) { - for (unsigned int i = 0; i < len; i++) { - chars_out[i] = tryte_to_char_mapping[trytes_in[i] + 13]; + for (unsigned int i = 0; i < trytes_len; i++) { + chars_out[i] = CHARS_TABLE[trytes_in[i] - MIN_TRYTE_VALUE]; } - return 0; } -/* --------------------- END trytes > chars */ -void chars_to_trits(const char *chars, trit_t *trits, unsigned int chars_len) +/** @brief Sets the last (3rd) trit in a single tryte to set to zero. + * @return value of the tryte without the last trit + */ +static tryte_t tryte_set_last_trit_zero(tryte_t tryte) { - tryte_t trytes[chars_len]; - chars_to_trytes(chars, trytes, chars_len); - trytes_to_trits(trytes, trits, chars_len); + if (tryte > MAX_TRYTE_VALUE - TRIT_4) { + return tryte - TRIT_4; + } + if (tryte < MIN_TRYTE_VALUE + TRIT_4) { + return tryte + TRIT_4; + } + return tryte; } -/** @brief Returns true, if the long little-endian integer represents a negative - * number in two's complement. +/** @brief Returns true, if the bigint represents a negative number in two's + * complement. */ static inline bool bigint_is_negative(const uint32_t *bigint) { // whether the most significant bit of the most significant byte is set - return (bigint[12 - 1] >> (sizeof(bigint[0]) * 8 - 1) != 0); + return (bigint[BIGINT_LENGTH - 1] >> (sizeof(bigint[0]) * 8 - 1) != 0); } +/** @brief Compares to bigints. + * @return -1 if a < b, 1 if a > b; or 0 if they are equal + */ static int bigint_cmp(const uint32_t *a, const uint32_t *b) { - for (unsigned int i = 12; i-- > 0;) { + for (unsigned int i = BIGINT_LENGTH; i-- > 0;) { if (a[i] < b[i]) { return -1; } @@ -126,7 +144,7 @@ static inline bool addcarry_u32(uint32_t *r, uint32_t a, uint32_t b, bool c_in) static bool bigint_add(uint32_t *r, const uint32_t *a, const uint32_t *b) { bool carry = false; - for (unsigned int i = 0; i < 12; i++) { + for (unsigned int i = 0; i < BIGINT_LENGTH; i++) { carry = addcarry_u32(&r[i], a[i], b[i], carry); } @@ -136,14 +154,14 @@ static bool bigint_add(uint32_t *r, const uint32_t *a, const uint32_t *b) static bool bigint_sub(uint32_t *r, const uint32_t *a, const uint32_t *b) { bool carry = true; - for (unsigned int i = 0; i < 12; i++) { + for (unsigned int i = 0; i < BIGINT_LENGTH; i++) { carry = addcarry_u32(&r[i], a[i], ~b[i], carry); } return carry; } -/** @brief adds a single 32-bit integer to a long little-endian integer. +/** @brief adds a single 32-bit integer to a bigint. * @return index of the most significant word which changed during the addition */ static unsigned int bigint_add_u32_mem(uint32_t *a, uint32_t summand) @@ -153,7 +171,7 @@ static unsigned int bigint_add_u32_mem(uint32_t *a, uint32_t summand) return 0; } - for (unsigned int i = 1; i < 12; i++) { + for (unsigned int i = 1; i < BIGINT_LENGTH; i++) { carry = addcarry_u32(&a[i], a[i], 0, true); if (carry == false) { return i; @@ -161,42 +179,42 @@ static unsigned int bigint_add_u32_mem(uint32_t *a, uint32_t summand) } // overflow - return 12; + return BIGINT_LENGTH; } -/** @brief multiplies a single 8-bit integer with a long little-endian integer. +/** @brief multiplies a single 32-bit integer with a bigint. * @param ms_index the index of the most significant non-zero word of the * input integer. Words after this are not considered. * @return the carry (one word) of the multiplication up to the byte which has the index specified in msb_index. */ -static uint32_t bigint_mult_byte_mem(uint32_t *a, uint8_t factor, - unsigned int ms_index) +static uint32_t bigint_mult_u32_mem(uint32_t *a, uint32_t factor, + unsigned int ms_index) { uint32_t carry = 0; for (unsigned int i = 0; i <= ms_index; i++) { const uint64_t v = (uint64_t)factor * a[i] + carry; - carry = v >> 32; - a[i] = v & 0xFFFFFFFF; + carry = v >> UINT32_WIDTH; + a[i] = v & UINT32_MAX; } return carry; } -/** @brief devides a long big-endian integer by a single 8-bit integer. +/** @brief devides a bigint by a single 32-bit integer. * @return remainder of the integer division. */ -static uint32_t bigint_div_byte_mem(uint32_t *a, uint8_t divisor) +static uint32_t bigint_div_u32_mem(uint32_t *a, uint32_t divisor) { uint32_t remainder = 0; - for (unsigned int i = 12; i-- > 0;) { - const uint64_t v = UINT64_C(0x100000000) * remainder + a[i]; + for (unsigned int i = BIGINT_LENGTH; i-- > 0;) { + const uint64_t v = (UINT64_C(1) + UINT32_MAX) * remainder + a[i]; - remainder = v % divisor; - a[i] = (v / divisor) & 0xFFFFFFFF; + remainder = (v % divisor) & UINT32_MAX; + a[i] = (v / divisor) & UINT32_MAX; } return remainder; @@ -223,30 +241,32 @@ static bool bigint_set_last_trit_zero(uint32_t *bigint) return false; } -/* --------------------- trits > bigint and back */ -static void trits_to_bigint(const trit_t *trits, uint32_t *bigint) +static void trytes_to_bigint(const tryte_t *trytes, uint32_t *bigint) { unsigned int ms_index = 0; // initialy there is no most significant word >0 - os_memset(bigint, 0, 12 * sizeof(bigint[0])); + os_memset(bigint, 0, BIGINT_LENGTH * sizeof(bigint[0])); + + // special case for the last tryte only holding two trits of value + bigint[0] = tryte_set_last_trit_zero(trytes[NUM_CHUNK_TRYTES - 1]) + 4; - // ignore the 243th trit, as it cannot be fully represented in 48 bytes - for (unsigned int i = 242; i-- > 0;) { + for (unsigned int i = NUM_CHUNK_TRYTES - 1; i-- > 0;) { // convert to non-balanced ternary - const uint8_t trit = trits[i] + 1; + const uint8_t tryte = trytes[i] + (TRYTE_BASE / 2); - const uint32_t carry = bigint_mult_byte_mem(bigint, BASE, ms_index); - if (carry > 0) { + const uint32_t carry = + bigint_mult_u32_mem(bigint, TRYTE_BASE, ms_index); + if (carry > 0 && ms_index < BIGINT_LENGTH - 1) { // if there is carry we need to use the next higher byte bigint[++ms_index] = carry; } - if (trit == 0) { + if (tryte == 0) { // nothing to add continue; } const unsigned int last_changed_index = - bigint_add_u32_mem(bigint, trit); + bigint_add_u32_mem(bigint, tryte); if (last_changed_index > ms_index) { ms_index = last_changed_index; } @@ -258,7 +278,14 @@ static void trits_to_bigint(const trit_t *trits, uint32_t *bigint) bigint_sub(bigint, bigint, HALF_3); } -static void bigint_to_trits_mem(uint32_t *bigint, trit_t *trits) +static void trits_to_bigint(const trit_t *trits, uint32_t *bigint) +{ + tryte_t trytes[NUM_HASH_TRYTES]; + trits_to_trytes(trits, trytes); + trytes_to_bigint(trytes, bigint); +} + +static void bigint_to_trytes_mem(uint32_t *bigint, tryte_t *trytes) { // the two's complement represention is only correct, if the number fits // into 48 bytes, i.e. has the 243th trit set to 0 @@ -267,16 +294,54 @@ static void bigint_to_trits_mem(uint32_t *bigint, trit_t *trits) // convert to the (positive) number representing non-balanced ternary bigint_add(bigint, bigint, HALF_3); - // ignore the 243th trit, as it cannot be fully represented in 48 bytes - for (unsigned int i = 0; i < 242; i++) { - const uint32_t rem = bigint_div_byte_mem(bigint, BASE); - trits[i] = rem - 1; // convert back to balanced + for (unsigned int i = 0; i < NUM_CHUNK_TRYTES - 1; i++) { + const uint32_t rem = bigint_div_u32_mem(bigint, TRYTE_BASE); + trytes[i] = rem - (TRYTE_BASE / 2); // convert back to balanced + } + + // special case for the last tryte, where no further division is necessary + trytes[NUM_CHUNK_TRYTES - 1] = + tryte_set_last_trit_zero(bigint[0] - (TRYTE_BASE / 2)); +} + +/** @brief Converts bigint consisting of 12 words into an array of bytes. + * It is represented using 48bytes in big-endiean, by reversing the order of + * the words. The endianness of the host machine is taken into account. + */ +static void bigint_to_bytes(const uint32_t *bigint, unsigned char *bytes) +{ + // reverse word order + for (unsigned int i = BIGINT_LENGTH; i-- > 0; bytes += 4) { + const uint32_t num = bigint[i]; + + bytes[0] = (num >> 24) & 0xFF; + bytes[1] = (num >> 16) & 0xFF; + bytes[2] = (num >> 8) & 0xFF; + bytes[3] = (num >> 0) & 0xFF; + } +} + +/** @brief Converts an array of 48 bytes into a bigint consisting of 12 words. + * The bigint is represented using 48bytes in big-endiean. The endianness of + * the host machine is taken into account. + */ +static void bytes_to_bigint(const unsigned char *bytes, uint32_t *bigint) +{ + // reverse word order + for (unsigned int i = BIGINT_LENGTH; i-- > 0; bytes += 4) { + bigint[i] = (uint32_t)bytes[0] << 24 | (uint32_t)bytes[1] << 16 | + (uint32_t)bytes[2] << 8 | (uint32_t)bytes[3] << 0; } - // set the last trit to zero for consistency - trits[242] = 0; } -bool int64_to_trits(const int64_t value, trit_t *trits, unsigned int num_trits) +void chars_to_trits(const char *chars, trit_t *trits, unsigned int chars_len) +{ + tryte_t trytes[chars_len]; + chars_to_trytes(chars, trytes, chars_len); + trytes_to_trits(trytes, trits, chars_len); +} + +bool s64_to_trits(const int64_t value, trit_t *trits, unsigned int num_trits) { os_memset(trits, 0, num_trits); @@ -304,9 +369,10 @@ bool int64_to_trits(const int64_t value, trit_t *trits, unsigned int num_trits) int rem = v_abs % BASE; v_abs = v_abs / BASE; - if (rem > 1) { - rem = -1; + if (rem > BASE / 2) { + // lend one from the next highest digit v_abs += 1; + rem -= BASE; } trits[i] = is_negative ? -rem : rem; @@ -314,89 +380,75 @@ bool int64_to_trits(const int64_t value, trit_t *trits, unsigned int num_trits) return v_abs != 0; } -/* --------------------- END trits > bigint */ -/** @brief Converts bigint consisting of 12 words into an array of bytes. - * It is represented using 48bytes in big-endiean, by reversing the order of - * the words. The endianness of the host machine is taken into account. - */ -static void bigint_to_bytes(const uint32_t *bigint, unsigned char *bytes) +bool u32_to_trits(const uint32_t value, trit_t *trits, unsigned int num_trits) { - // reverse word order - for (unsigned int i = 12; i-- > 0; bytes += 4) { - const uint32_t num = bigint[i]; + uint32_t v = value; + os_memset(trits, 0, num_trits); - bytes[0] = (num >> 24) & 0xFF; - bytes[1] = (num >> 16) & 0xFF; - bytes[2] = (num >> 8) & 0xFF; - bytes[3] = (num >> 0) & 0xFF; - } -} + for (unsigned int i = 0; i < num_trits; i++) { + if (v == 0) { + return false; + } -/** @brief Converts an array of 48 bytes into a bigint consisting of 12 words. - * The bigint is represented using 48bytes in big-endiean. The endianness of - * the host machine is taken into account. - */ -static void bytes_to_bigint(const unsigned char *bytes, uint32_t *bigint) -{ - // reverse word order - for (unsigned int i = 12; i-- > 0; bytes += 4) { - bigint[i] = (uint32_t)bytes[0] << 24 | (uint32_t)bytes[1] << 16 | - (uint32_t)bytes[2] << 8 | (uint32_t)bytes[3] << 0; + int rem = v % BASE; + v = v / BASE; + if (rem > BASE / 2) { + // lend one from the next highest digit + v += 1; + rem -= BASE; + } + + trits[i] = rem; } -} -/** @brief Converts a big-endian binary integer into ternary representation. - * @param bytes input big-endian 48-byte integers - * @param trits target trit array - */ -static void bytes_to_trits(const unsigned char *bytes, trit_t *trits) -{ - uint32_t bigint[12]; - bytes_to_bigint(bytes, bigint); - bigint_to_trits_mem(bigint, trits); + return v != 0; } void trits_to_bytes(const trit_t *trits, unsigned char *bytes) { - uint32_t bigint[12]; + uint32_t bigint[BIGINT_LENGTH]; trits_to_bigint(trits, bigint); bigint_to_bytes(bigint, bytes); } -void chars_to_bytes(const char *chars, unsigned char *bytes, - unsigned int chars_len) +static void trytes_to_bytes(const tryte_t *trytes, unsigned char *bytes) { - for (unsigned int i = 0; i < chars_len / 81; i++) { - trit_t trits[243]; - chars_to_trits(chars + i * 81, trits, 81); - // bigint can only handle 242 trits - trits[242] = 0; - - trits_to_bytes(trits, bytes + i * 48); - } + uint32_t bigint[BIGINT_LENGTH]; + trytes_to_bigint(trytes, bigint); + bigint_to_bytes(bigint, bytes); } void bytes_to_trytes(const unsigned char *bytes, tryte_t *trytes) { - trit_t trits[243]; - bytes_to_trits(bytes, trits); - trits_to_trytes(trits, trytes, 243); + uint32_t bigint[BIGINT_LENGTH]; + bytes_to_bigint(bytes, bigint); + bigint_to_trytes_mem(bigint, trytes); +} + +void chars_to_bytes(const char *chars, unsigned char *bytes, + unsigned int chars_len) +{ + for (unsigned int i = 0; i < chars_len / NUM_CHUNK_TRYTES; i++) { + tryte_t trytes[NUM_CHUNK_TRYTES]; + chars_to_trytes(chars + i * NUM_CHUNK_TRYTES, trytes, NUM_CHUNK_TRYTES); + trytes_to_bytes(trytes, bytes + i * NUM_CHUNK_BYTES); + } } void bytes_to_chars(const unsigned char *bytes, char *chars, unsigned int bytes_len) { - for (unsigned int i = 0; i < bytes_len / 48; i++) { - tryte_t trytes[81]; - bytes_to_trytes(bytes + i * 48, trytes); - trytes_to_chars(trytes, chars + i * 81, 81); + for (unsigned int i = 0; i < bytes_len / NUM_CHUNK_BYTES; i++) { + tryte_t trytes[NUM_CHUNK_TRYTES]; + bytes_to_trytes(bytes + i * NUM_CHUNK_BYTES, trytes); + trytes_to_chars(trytes, chars + i * NUM_CHUNK_TRYTES, NUM_CHUNK_TRYTES); } } void bytes_set_last_trit_zero(unsigned char *bytes) { - uint32_t bigint[12]; + uint32_t bigint[BIGINT_LENGTH]; bytes_to_bigint(bytes, bigint); if (bigint_set_last_trit_zero(bigint)) { bigint_to_bytes(bigint, bytes); @@ -406,7 +458,7 @@ void bytes_set_last_trit_zero(unsigned char *bytes) void bytes_add_u32_mem(unsigned char *bytes, uint32_t summand) { if (summand > 0) { - uint32_t bigint[12]; + uint32_t bigint[BIGINT_LENGTH]; bytes_to_bigint(bytes, bigint); bigint_add_u32_mem(bigint, summand); diff --git a/src/iota/conversion.h b/src/iota/conversion.h index 2691f6ab..7c06a15d 100644 --- a/src/iota/conversion.h +++ b/src/iota/conversion.h @@ -24,7 +24,16 @@ void chars_to_trits(const char *chars, trit_t *trits, unsigned int chars_len); * @return true, if an overflow occured and the given integer could not be completely represented with this number of trits, false otherwise. */ -bool int64_to_trits(const int64_t value, trit_t *trits, unsigned int num_trits); +bool s64_to_trits(const int64_t value, trit_t *trits, unsigned int num_trits); + +/** @brief Converts a single unsigned integer into its ternary representation. + * @param value signed integer to convert + * @param trits target trit array + * @param num_trits number of trits to convert + * @return true, if an overflow occured and the given integer could not be + completely represented with this number of trits, false otherwise. + */ +bool u32_to_trits(const uint32_t value, trit_t *trits, unsigned int num_trits); /** @brief Converts a balanced ternary number into a big-endian binary integer. * The input must consist of exactly one 243-trit chunk and is converted into @@ -53,17 +62,6 @@ void bytes_to_trytes(const unsigned char *bytes, tryte_t *trytes); void chars_to_bytes(const char *chars, unsigned char *bytes, unsigned int chars_len); -/** @brief Converts an array of chars into a balanced ternary number - * in tryte (3-trit) representation. - * The input must consist of multiples of 81-char chunks, each chunk is - * converted into a big-endian 48-byte integer - * @param chars_in base-27 encoded ternary number - * @param trytes_out target tryte array - * @param len length of the input - */ -int chars_to_trytes(const char chars_in[], tryte_t trytes_out[], - unsigned int len); - /** @brief Converts a big-endian binary integer into a balanced ternary number * in base-27 encoding. * The input must consist of one or more big-endian 48-byte integers, each diff --git a/tests/bundle_ext.c b/tests/bundle_ext.c index d63e747d..a38bee84 100644 --- a/tests/bundle_ext.c +++ b/tests/bundle_ext.c @@ -11,6 +11,13 @@ typedef struct TX_ENTRY { uint32_t timestamp; } TX_ENTRY; +static void bytes_to_trits(const unsigned char *bytes, trit_t *trits) +{ + tryte_t trytes[NUM_HASH_TRYTES]; + bytes_to_trytes(bytes, trytes); + trytes_to_trits(trytes, trits, NUM_HASH_TRYTES); +} + static void increment_trit_aera(trit_t *trits, unsigned int start_trit, unsigned int num_trits) { diff --git a/tests/conversion_test.c b/tests/conversion_test.c index d597cfe7..fe2c4b09 100644 --- a/tests/conversion_test.c +++ b/tests/conversion_test.c @@ -5,7 +5,7 @@ #define NUM_RANDOM_TESTS 10000 -static void test_int64_to_trits_zero(void **state) +static void test_s64_to_trits_zero(void **state) { UNUSED(state); @@ -13,13 +13,13 @@ static void test_int64_to_trits_zero(void **state) static const trit_t expected_trits[42] = {0}; trit_t trits_out[42]; - bool result = int64_to_trits(input_value, trits_out, 42); + bool result = s64_to_trits(input_value, trits_out, 42); assert_false(result); assert_memory_equal(trits_out, expected_trits, 42); } -static void test_int64_to_trits_one(void **state) +static void test_s64_to_trits_one(void **state) { UNUSED(state); @@ -28,13 +28,13 @@ static void test_int64_to_trits_one(void **state) memset(expected_trits, 1, 40); trit_t trits_out[40]; - bool result = int64_to_trits(input_value, trits_out, 40); + bool result = s64_to_trits(input_value, trits_out, 40); assert_false(result); assert_memory_equal(trits_out, expected_trits, 40); } -static void test_int64_to_trits_neg_one(void **state) +static void test_s64_to_trits_neg_one(void **state) { UNUSED(state); @@ -43,25 +43,25 @@ static void test_int64_to_trits_neg_one(void **state) memset(expected_trits, -1, 40); trit_t trits_out[40]; - bool result = int64_to_trits(input_value, trits_out, 40); + bool result = s64_to_trits(input_value, trits_out, 40); assert_false(result); assert_memory_equal(trits_out, expected_trits, 40); } -static void test_int64_to_trits_overflow(void **state) +static void test_s64_to_trits_overflow(void **state) { UNUSED(state); static const int64_t input_value = 6078832729528464401; trit_t trits_out[40]; - bool result = int64_to_trits(input_value, trits_out, 40); + bool result = s64_to_trits(input_value, trits_out, 40); assert_true(result); } -static void test_int64_to_trits_int_min(void **state) +static void test_s64_to_trits_int_min(void **state) { UNUSED(state); @@ -72,12 +72,53 @@ static void test_int64_to_trits_int_min(void **state) 0, -1, -1, -1, 0, 0, -1, -1, -1, 1, -1, 1, -1}; trit_t trits_out[41]; - bool result = int64_to_trits(input_value, trits_out, 41); + bool result = s64_to_trits(input_value, trits_out, 41); assert_false(result); assert_memory_equal(trits_out, expected_trits, 41); } +static void test_u32_to_trits_zero(void **state) +{ + UNUSED(state); + + static const uint32_t input_value = 0; + static const trit_t expected_trits[21] = {0}; + + trit_t trits_out[21]; + bool result = u32_to_trits(input_value, trits_out, 21); + + assert_false(result); + assert_memory_equal(trits_out, expected_trits, 21); +} + +static void test_u32_to_trits_one(void **state) +{ + UNUSED(state); + + static const uint32_t input_value = 1743392200; // \sum_{i=0}^{19} 3^i + trit_t expected_trits[20]; + memset(expected_trits, 1, 20); + + trit_t trits_out[20]; + bool result = u32_to_trits(input_value, trits_out, 20); + + assert_false(result); + assert_memory_equal(trits_out, expected_trits, 20); +} + +static void test_u32_to_trits_overflow(void **state) +{ + UNUSED(state); + + static const uint32_t input_value = 1743392201; + + trit_t trits_out[20]; + bool result = u32_to_trits(input_value, trits_out, 20); + + assert_true(result); +} + static void random_bytes(unsigned char *bytes) { for (int i = 0; i < NUM_HASH_BYTES; i++) { @@ -206,11 +247,14 @@ static void test_random_chars_via_bytes(void **state) int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test(test_int64_to_trits_zero), - cmocka_unit_test(test_int64_to_trits_one), - cmocka_unit_test(test_int64_to_trits_neg_one), - cmocka_unit_test(test_int64_to_trits_overflow), - cmocka_unit_test(test_int64_to_trits_int_min), + cmocka_unit_test(test_s64_to_trits_zero), + cmocka_unit_test(test_s64_to_trits_one), + cmocka_unit_test(test_s64_to_trits_neg_one), + cmocka_unit_test(test_s64_to_trits_overflow), + cmocka_unit_test(test_s64_to_trits_int_min), + cmocka_unit_test(test_u32_to_trits_zero), + cmocka_unit_test(test_u32_to_trits_one), + cmocka_unit_test(test_u32_to_trits_overflow), cmocka_unit_test(test_all_zero), cmocka_unit_test(test_all_one), cmocka_unit_test(test_all_neg_one),