diff --git a/Sources/Crypto/base58.c b/Sources/Crypto/base58.c old mode 100755 new mode 100644 index 5afbbd0..2799977 --- a/Sources/Crypto/base58.c +++ b/Sources/Crypto/base58.c @@ -1,6 +1,7 @@ /** * Copyright (c) 2012-2014 Luke Dashjr * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2019 Johan Nordberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -21,261 +22,169 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include "include/base58.h" + #include -#include -#include "base58.h" -#include "sha2.h" -#include "ripemd160.h" +#include + #include "memzero.h" -static const int8_t b58digits_map[] = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1, - -1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1, - 22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1, - -1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46, - 47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1, +const char b58digits_ordered[] = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +const int8_t b58digits_map[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, + 8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, + 19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, + -1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1, }; -bool b58tobin(void *bin, size_t *binszp, const char *b58) -{ - size_t binsz = *binszp; - const unsigned char *b58u = (const unsigned char*)b58; - unsigned char *binu = bin; - size_t outisz = (binsz + 3) / 4; - uint32_t outi[outisz]; - uint64_t t; - uint32_t c; - size_t i, j; - uint8_t bytesleft = binsz % 4; - uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0; - unsigned zerocount = 0; - size_t b58sz; - - b58sz = strlen(b58); - - memset(outi, 0, outisz * sizeof(*outi)); - - // Leading zeros, just count - for (i = 0; i < b58sz && b58u[i] == '1'; ++i) - ++zerocount; - - for ( ; i < b58sz; ++i) - { - if (b58u[i] & 0x80) - // High-bit set on invalid digit - return false; - if (b58digits_map[b58u[i]] == -1) - // Invalid base58 digit - return false; - c = (unsigned)b58digits_map[b58u[i]]; - for (j = outisz; j--; ) - { - t = ((uint64_t)outi[j]) * 58 + c; - c = (t & 0x3f00000000) >> 32; - outi[j] = t & 0xffffffff; - } - if (c) - // Output number too big (carry to the next int32) - return false; - if (outi[0] & zeromask) - // Output number too big (last int32 filled too far) - return false; - } - - j = 0; - switch (bytesleft) { - case 3: - *(binu++) = (outi[0] & 0xff0000) >> 16; - //-fallthrough - case 2: - *(binu++) = (outi[0] & 0xff00) >> 8; - //-fallthrough - case 1: - *(binu++) = (outi[0] & 0xff); - ++j; - //-fallthrough - default: - break; - } - - for (; j < outisz; ++j) - { - *(binu++) = (outi[j] >> 0x18) & 0xff; - *(binu++) = (outi[j] >> 0x10) & 0xff; - *(binu++) = (outi[j] >> 8) & 0xff; - *(binu++) = (outi[j] >> 0) & 0xff; - } - - // Count canonical base58 byte count - binu = bin; - for (i = 0; i < binsz; ++i) - { - if (binu[i]) { - if (zerocount > i) { - /* result too large */ - return false; - } - break; - } - --*binszp; - } - *binszp += zerocount; - - return true; -} - -int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str) -{ - unsigned char buf[32]; - const uint8_t *binc = bin; - unsigned i; - if (binsz < 4) - return -4; - hasher_Raw(hasher_type, bin, binsz - 4, buf); - if (memcmp(&binc[binsz - 4], buf, 4)) - return -1; - - // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) - {} // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') - return -3; - - return binc[0]; +typedef uint64_t b58_maxint_t; +typedef uint32_t b58_almostmaxint_t; +#define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) +static const b58_almostmaxint_t b58_almostmaxint_mask = + ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); + +bool b58tobin(void *bin, size_t *binszp, const char *b58) { + size_t binsz = *binszp; + + if (binsz == 0) { + return false; + } + + const unsigned char *b58u = (const unsigned char *)b58; + unsigned char *binu = bin; + size_t outisz = + (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); + b58_almostmaxint_t outi[outisz]; + b58_maxint_t t = 0; + b58_almostmaxint_t c = 0; + size_t i = 0, j = 0; + uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t); + b58_almostmaxint_t zeromask = + bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0; + unsigned zerocount = 0; + + size_t b58sz = strlen(b58); + + memzero(outi, sizeof(outi)); + + // Leading zeros, just count + for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; + + for (; i < b58sz; ++i) { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits_map[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = (unsigned)b58digits_map[b58u[i]]; + for (j = outisz; j--;) { + t = ((b58_maxint_t)outi[j]) * 58 + c; + c = t >> b58_almostmaxint_bits; + outi[j] = t & b58_almostmaxint_mask; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + j = 0; + if (bytesleft) { + for (i = bytesleft; i > 0; --i) { + *(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff; + } + ++j; + } + + for (; j < outisz; ++j) { + for (i = sizeof(*outi); i > 0; --i) { + *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; + } + } + + // Count canonical base58 byte count + binu = bin; + for (i = 0; i < binsz; ++i) { + if (binu[i]) { + if (zerocount > i) { + /* result too large */ + return false; + } + + break; + } + --*binszp; + } + *binszp += zerocount; + + return true; } -static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) -{ - const uint8_t *bin = data; - int carry; - ssize_t i, j, high, zcount = 0; - size_t size; - - while (zcount < (ssize_t)binsz && !bin[zcount]) - ++zcount; - - size = (binsz - zcount) * 138 / 100 + 1; - uint8_t buf[size]; - memset(buf, 0, size); - - for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) - { - for (carry = bin[i], j = size - 1; (j > high) || carry; --j) - { - carry += 256 * buf[j]; - buf[j] = carry % 58; - carry /= 58; - } - } - - for (j = 0; j < (ssize_t)size && !buf[j]; ++j); - - if (*b58sz <= zcount + size - j) - { - *b58sz = zcount + size - j + 1; - return false; - } - - if (zcount) - memset(b58, '1', zcount); - for (i = zcount; j < (ssize_t)size; ++i, ++j) - b58[i] = b58digits_ordered[buf[j]]; - b58[i] = '\0'; - *b58sz = i + 1; - - return true; -} - -int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type, char *str, int strsize) -{ - if (datalen > 128) { - return 0; - } - uint8_t buf[datalen + 32]; - uint8_t *hash = buf + datalen; - memcpy(buf, data, datalen); - hasher_Raw(hasher_type, data, datalen, hash); - size_t res = strsize; - bool success = b58enc(str, &res, buf, datalen + 4); - memzero(buf, sizeof(buf)); - return success ? res : 0; -} - -int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen) -{ - if (datalen > 128) { - return 0; - } - uint8_t d[datalen + 4]; - size_t res = datalen + 4; - if (b58tobin(d, &res, str) != true) { - return 0; - } - uint8_t *nd = d + datalen + 4 - res; - if (b58check(nd, res, hasher_type, str) < 0) { - return 0; - } - memcpy(data, nd, res - 4); - return res - 4; -} - -#if USE_GRAPHENE -int b58gphcheck(const void *bin, size_t binsz, const char *base58str) -{ - unsigned char buf[32]; - const uint8_t *binc = bin; - unsigned i; - if (binsz < 4) - return -4; - ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160 - if (memcmp(&binc[binsz - 4], buf, 4)) - return -1; - - // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) - for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) - {} // Just finding the end of zeros, nothing to do in loop - if (binc[i] == '\0' || base58str[i] == '1') - return -3; - - return binc[0]; +bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { + const uint8_t *bin = data; + int carry = 0; + size_t i = 0, j = 0, high = 0, zcount = 0; + size_t size = 0; + + while (zcount < binsz && !bin[zcount]) ++zcount; + + size = (binsz - zcount) * 138 / 100 + 1; + uint8_t buf[size]; + memzero(buf, size); + + for (i = zcount, high = size - 1; i < binsz; ++i, high = j) { + for (carry = bin[i], j = size - 1; (j > high) || carry; --j) { + carry += 256 * buf[j]; + buf[j] = carry % 58; + carry /= 58; + if (!j) { + // Otherwise j wraps to maxint which is > high + break; + } + } + } + + for (j = 0; j < size && !buf[j]; ++j) + ; + + if (*b58sz <= zcount + size - j) { + *b58sz = zcount + size - j + 1; + return false; + } + + if (zcount) memset(b58, '1', zcount); + for (i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]]; + b58[i] = '\0'; + *b58sz = i + 1; + + return true; } -int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize) -{ - if (datalen > 128) { - return 0; - } - uint8_t buf[datalen + 32]; - uint8_t *hash = buf + datalen; - memcpy(buf, data, datalen); - ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160 - size_t res = strsize; - bool success = b58enc(str, &res, buf, datalen + 4); - memzero(buf, sizeof(buf)); - return success ? res : 0; +size_t base58_encode(const uint8_t *data, size_t datalen, char *str, + size_t strsize) { + size_t res = strsize; + if (!b58enc(str, &res, data, datalen)) { + return 0; + } + return res; } -int base58gph_decode_check(const char *str, uint8_t *data, int datalen) -{ - if (datalen > 128) { - return 0; - } - uint8_t d[datalen + 4]; - size_t res = datalen + 4; - if (b58tobin(d, &res, str) != true) { - return 0; - } - uint8_t *nd = d + datalen + 4 - res; - if (b58gphcheck(nd, res, str) < 0) { - return 0; - } - memcpy(data, nd, res - 4); - return res - 4; +size_t base58_decode(const char *str, uint8_t *data, size_t datalen) { + uint8_t d[datalen]; + memset(d, 0, sizeof(d)); + size_t res = datalen; + if (b58tobin(d, &res, str) != true) { + return 0; + } + uint8_t *nd = d + datalen - res; + memcpy(data, nd, res); + return res; } -#endif diff --git a/Sources/Crypto/hasher.c b/Sources/Crypto/hasher.c deleted file mode 100755 index c9af3cf..0000000 --- a/Sources/Crypto/hasher.c +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "hasher.h" - -void hasher_Init(Hasher *hasher, HasherType type) { - hasher->type = type; - - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - sha256_Init(&hasher->ctx.sha2); - break; - // case HASHER_BLAKE: - // case HASHER_BLAKED: - // blake256_Init(&hasher->ctx.blake); - // break; - // case HASHER_GROESTLD_TRUNC: - // groestl512_Init(&hasher->ctx.groestl); - // break; - } -} - -void hasher_Reset(Hasher *hasher) { - hasher_Init(hasher, hasher->type); -} - -void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - sha256_Update(&hasher->ctx.sha2, data, length); - break; - // case HASHER_BLAKE: - // case HASHER_BLAKED: - // blake256_Update(&hasher->ctx.blake, data, length); - // break; - // case HASHER_GROESTLD_TRUNC: - // groestl512_Update(&hasher->ctx.groestl, data, length); - // break; - } -} - -void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { - switch (hasher->type) { - case HASHER_SHA2: - case HASHER_SHA2D: - sha256_Final(&hasher->ctx.sha2, hash); - break; - // case HASHER_BLAKE: - // case HASHER_BLAKED: - // blake256_Final(&hasher->ctx.blake, hash); - // break; - // case HASHER_GROESTLD_TRUNC: - // groestl512_DoubleTrunc(&hasher->ctx.groestl, hash); - // return; - } - - switch (hasher->type) { - case HASHER_SHA2D: - hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash); - break; - // case HASHER_BLAKED: - // hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash); - // break; - default: - break; - } -} - -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { - Hasher hasher; - - hasher_Init(&hasher, type); - hasher_Update(&hasher, data, length); - hasher_Final(&hasher, hash); -} diff --git a/Sources/Crypto/hasher.h b/Sources/Crypto/hasher.h deleted file mode 100755 index ca31fc8..0000000 --- a/Sources/Crypto/hasher.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2017 Saleem Rashid - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __HASHER_H__ -#define __HASHER_H__ - -#include -#include - -#include "sha2.h" -// #include "blake256.h" -// #include "groestl.h" - -#define HASHER_DIGEST_LENGTH 32 - -typedef enum { - HASHER_SHA2, - // HASHER_BLAKE, - - HASHER_SHA2D, - // HASHER_BLAKED, - - // HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */ -} HasherType; - -typedef struct { - HasherType type; - - union { - SHA256_CTX sha2; -// BLAKE256_CTX blake; -// GROESTL512_CTX groestl; - } ctx; -} Hasher; - -void hasher_Init(Hasher *hasher, HasherType type); -void hasher_Reset(Hasher *hasher); -void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); -void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); - -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); - -#endif diff --git a/Sources/Crypto/base58.h b/Sources/Crypto/include/base58.h old mode 100755 new mode 100644 similarity index 62% rename from Sources/Crypto/base58.h rename to Sources/Crypto/include/base58.h index 41b0b7d..f3d29a7 --- a/Sources/Crypto/base58.h +++ b/Sources/Crypto/include/base58.h @@ -1,6 +1,7 @@ /** * Copyright (c) 2013-2014 Tomas Dzetkulic * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2019 Johan Nordberg * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the "Software"), @@ -24,23 +25,11 @@ #ifndef __BASE58_H__ #define __BASE58_H__ +#include #include -#include -#include "hasher.h" -#include "options.h" -int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize); -int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen); - -// Private -bool b58tobin(void *bin, size_t *binszp, const char *b58); -int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str); -bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz); - -#if USE_GRAPHENE -int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize); -int base58gph_decode_check(const char *str, uint8_t *data, int datalen); -int b58gphcheck(const void *bin, size_t binsz, const char *base58str); -#endif +size_t base58_encode(const uint8_t *data, size_t datalen, char *str, + size_t strsize); +size_t base58_decode(const char *str, uint8_t *data, size_t datalen); #endif diff --git a/Sources/Crypto/include/crypto.h b/Sources/Crypto/include/crypto.h index 2165d74..5874bf8 100644 --- a/Sources/Crypto/include/crypto.h +++ b/Sources/Crypto/include/crypto.h @@ -1,6 +1,8 @@ -#ifndef CRYPTO_H__ -#define CRYPTO_H__ +#ifndef __CRYPTO_H__ +#define __CRYPTO_H__ -#include "../base58.h" +#include "base58.h" +#include "ripemd160.h" +#include "sha2.h" -#endif \ No newline at end of file +#endif diff --git a/Sources/Crypto/include/ripemd160.h b/Sources/Crypto/include/ripemd160.h new file mode 100644 index 0000000..8256b08 --- /dev/null +++ b/Sources/Crypto/include/ripemd160.h @@ -0,0 +1,22 @@ +#ifndef __RIPEMD160_H__ +#define __RIPEMD160_H__ + +#include + +#define RIPEMD160_BLOCK_LENGTH 64 +#define RIPEMD160_DIGEST_LENGTH 20 + +typedef struct _RIPEMD160_CTX { + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ +} RIPEMD160_CTX; + +void ripemd160_Init(RIPEMD160_CTX *ctx); +void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); +void ripemd160_Final(RIPEMD160_CTX *ctx, + uint8_t output[RIPEMD160_DIGEST_LENGTH]); +void ripemd160(const uint8_t *msg, uint32_t msg_len, + uint8_t hash[RIPEMD160_DIGEST_LENGTH]); + +#endif diff --git a/Sources/Crypto/sha2.h b/Sources/Crypto/include/sha2.h old mode 100755 new mode 100644 similarity index 98% rename from Sources/Crypto/sha2.h rename to Sources/Crypto/include/sha2.h index 7f519c5..7c468c4 --- a/Sources/Crypto/sha2.h +++ b/Sources/Crypto/include/sha2.h @@ -74,7 +74,7 @@ typedef struct _SHA512_CTX { #define REVERSE32(w,x) { \ uint32_t tmp = (w); \ tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ + (x) = ((tmp & (uint32_t)0xff00ff00UL) >> 8) | ((tmp & (uint32_t)0x00ff00ffUL) << 8); \ } #define REVERSE64(w,x) { \ uint64_t tmp = (w); \ diff --git a/Sources/Crypto/memzero.c b/Sources/Crypto/memzero.c old mode 100755 new mode 100644 index 68fad58..6a517ff --- a/Sources/Crypto/memzero.c +++ b/Sources/Crypto/memzero.c @@ -1,6 +1,66 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface. +#endif #include -void memzero(void *s, size_t n) -{ - memset(s, 0, n); +#ifdef _WIN32 +#include +#endif + +#ifdef __unix__ +#include +#include +#endif + +// C11's bounds-checking interface. +#if defined(__STDC_LIB_EXT1__) +#define HAVE_MEMSET_S 1 +#endif + +// GNU C Library version 2.25 or later. +#if defined(__GLIBC__) && \ + (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// Newlib +#if defined(__NEWLIB__) +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// FreeBSD version 11.0 or later. +#if defined(__FreeBSD__) && __FreeBSD_version >= 1100037 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// OpenBSD version 5.5 or later. +#if defined(__OpenBSD__) && OpenBSD >= 201405 +#define HAVE_EXPLICIT_BZERO 1 +#endif + +// NetBSD version 7.2 or later. +#if defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 +#define HAVE_EXPLICIT_MEMSET 1 +#endif + +// Adapted from +// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130 + +void memzero(void *const pnt, const size_t len) { +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + memset_s(pnt, (rsize_t)len, 0, (rsize_t)len); +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif defined(HAVE_EXPLICIT_MEMSET) + explicit_memset(pnt, 0, len); +#else + volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt; + size_t i = (size_t)0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif } diff --git a/Sources/Crypto/memzero.h b/Sources/Crypto/memzero.h old mode 100755 new mode 100644 index ce51aca..0a959fb --- a/Sources/Crypto/memzero.h +++ b/Sources/Crypto/memzero.h @@ -3,6 +3,6 @@ #include -void memzero(void *s, size_t n); +void memzero(void* const pnt, const size_t len); #endif diff --git a/Sources/Crypto/options.h b/Sources/Crypto/options.h deleted file mode 100755 index e74d004..0000000 --- a/Sources/Crypto/options.h +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2013-2014 Pavol Rusnak - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES - * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __OPTIONS_H__ -#define __OPTIONS_H__ - -// use precomputed Curve Points (some scalar multiples of curve base point G) -#ifndef USE_PRECOMPUTED_CP -#define USE_PRECOMPUTED_CP 1 -#endif - -// use fast inverse method -#ifndef USE_INVERSE_FAST -#define USE_INVERSE_FAST 1 -#endif - -// support for printing bignum256 structures via printf -#ifndef USE_BN_PRINT -#define USE_BN_PRINT 0 -#endif - -// use deterministic signatures -#ifndef USE_RFC6979 -#define USE_RFC6979 1 -#endif - -// implement BIP32 caching -#ifndef USE_BIP32_CACHE -#define USE_BIP32_CACHE 1 -#define BIP32_CACHE_SIZE 10 -#define BIP32_CACHE_MAXDEPTH 8 -#endif - -// support constructing BIP32 nodes from ed25519 and curve25519 curves. -#ifndef USE_BIP32_25519_CURVES -#define USE_BIP32_25519_CURVES 1 -#endif - -// implement BIP39 caching -#ifndef USE_BIP39_CACHE -#define USE_BIP39_CACHE 1 -#define BIP39_CACHE_SIZE 4 -#endif - -// support Ethereum operations -#ifndef USE_ETHEREUM -#define USE_ETHEREUM 0 -#endif - -// support Graphene operations (VIZ, BitShares) -#ifndef USE_GRAPHENE -#define USE_GRAPHENE 1 -#endif - -// support NEM operations -#ifndef USE_NEM -#define USE_NEM 0 -#endif - -// support MONERO operations -#ifndef USE_MONERO -#define USE_MONERO 0 -#endif - -// support Keccak hashing -#ifndef USE_KECCAK -#define USE_KECCAK 1 -#endif - -// add way how to mark confidential data -#ifndef CONFIDENTIAL -#define CONFIDENTIAL -#endif - -#endif diff --git a/Sources/Crypto/ripemd160.c b/Sources/Crypto/ripemd160.c old mode 100755 new mode 100644 index 66b13ca..352c4e9 --- a/Sources/Crypto/ripemd160.c +++ b/Sources/Crypto/ripemd160.c @@ -25,9 +25,10 @@ * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 */ +#include "include/ripemd160.h" + #include -#include "ripemd160.h" #include "memzero.h" /* @@ -58,7 +59,7 @@ */ void ripemd160_Init(RIPEMD160_CTX *ctx) { - memset(ctx, 0, sizeof(RIPEMD160_CTX)); + memzero(ctx, sizeof(RIPEMD160_CTX)); ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; @@ -74,7 +75,7 @@ void ripemd160_Init(RIPEMD160_CTX *ctx) */ void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[RIPEMD160_BLOCK_LENGTH] ) { - uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; + uint32_t A = 0, B = 0, C = 0, D = 0, E = 0, Ap = 0, Bp = 0, Cp = 0, Dp = 0, Ep = 0, X[16] = {0}; GET_UINT32_LE( X[ 0], data, 0 ); GET_UINT32_LE( X[ 1], data, 4 ); @@ -255,8 +256,8 @@ void ripemd160_process( RIPEMD160_CTX *ctx, const uint8_t data[RIPEMD160_BLOCK_L */ void ripemd160_Update( RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen ) { - uint32_t fill; - uint32_t left; + uint32_t fill = 0; + uint32_t left = 0; if( ilen == 0 ) return; @@ -305,9 +306,9 @@ static const uint8_t ripemd160_padding[RIPEMD160_BLOCK_LENGTH] = */ void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH] ) { - uint32_t last, padn; - uint32_t high, low; - uint8_t msglen[8]; + uint32_t last = 0; uint32_t padn = 0; + uint32_t high = 0; uint32_t low = 0; + uint8_t msglen[8] = {0}; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); @@ -336,7 +337,7 @@ void ripemd160_Final( RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH */ void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]) { - RIPEMD160_CTX ctx; + RIPEMD160_CTX ctx = {0}; ripemd160_Init( &ctx ); ripemd160_Update( &ctx, msg, msg_len ); ripemd160_Final( &ctx, hash ); diff --git a/Sources/Crypto/ripemd160.h b/Sources/Crypto/ripemd160.h deleted file mode 100755 index a62de5c..0000000 --- a/Sources/Crypto/ripemd160.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __RIPEMD160_H__ -#define __RIPEMD160_H__ - -#include - -#define RIPEMD160_BLOCK_LENGTH 64 -#define RIPEMD160_DIGEST_LENGTH 20 - -typedef struct _RIPEMD160_CTX { - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[5]; /*!< intermediate digest state */ - uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */ -} RIPEMD160_CTX; - -void ripemd160_Init(RIPEMD160_CTX *ctx); -void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen); -void ripemd160_Final(RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH]); -void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]); - -#endif diff --git a/Sources/Crypto/sha2.c b/Sources/Crypto/sha2.c old mode 100755 new mode 100644 index 39c1aac..b37e5cb --- a/Sources/Crypto/sha2.c +++ b/Sources/Crypto/sha2.c @@ -321,10 +321,10 @@ void sha1_Init(SHA1_CTX* context) { j++; void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a, b, c, d, e; - sha2_word32 T1; - sha2_word32 W1[16]; - int j; + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; /* Initialize registers with the prev. intermediate value */ a = state_in[0]; @@ -439,10 +439,10 @@ void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_w #else /* SHA2_UNROLL_TRANSFORM */ void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a, b, c, d, e; - sha2_word32 T1; - sha2_word32 W1[16]; - int j; + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0; + sha2_word32 T1 = 0; + sha2_word32 W1[16] = {0}; + int j = 0; /* Initialize registers with the prev. intermediate value */ a = state_in[0]; @@ -520,7 +520,7 @@ void sha1_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_w #endif /* SHA2_UNROLL_TRANSFORM */ void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; + unsigned int freespace = 0, usedspace = 0; if (len == 0) { /* Calling with no data is valid - we do nothing */ @@ -578,7 +578,7 @@ void sha1_Update(SHA1_CTX* context, const sha2_byte *data, size_t len) { } void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { - unsigned int usedspace; + unsigned int usedspace = 0; /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { @@ -632,8 +632,8 @@ void sha1_Final(SHA1_CTX* context, sha2_byte digest[]) { } char *sha1_End(SHA1_CTX* context, char buffer[]) { - sha2_byte digest[SHA1_DIGEST_LENGTH], *d = digest; - int i; + sha2_byte digest[SHA1_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; if (buffer != (char*)0) { sha1_Final(context, digest); @@ -652,14 +652,14 @@ char *sha1_End(SHA1_CTX* context, char buffer[]) { } void sha1_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA1_DIGEST_LENGTH]) { - SHA1_CTX context; + SHA1_CTX context = {0}; sha1_Init(&context); sha1_Update(&context, data, len); sha1_Final(&context, digest); } char* sha1_Data(const sha2_byte* data, size_t len, char digest[SHA1_DIGEST_STRING_LENGTH]) { - SHA1_CTX context; + SHA1_CTX context = {0}; sha1_Init(&context); sha1_Update(&context, data, len); @@ -699,10 +699,10 @@ void sha256_Init(SHA256_CTX* context) { j++ void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1; - sha2_word32 W256[16]; - int j; + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0; + sha2_word32 W256[16] = {0}; + int j = 0; /* Initialize registers with the prev. intermediate value */ a = state_in[0]; @@ -756,9 +756,9 @@ void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2 #else /* SHA2_UNROLL_TRANSFORM */ void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2_word32* state_out) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, T2, W256[16]; - int j; + sha2_word32 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word32 T1 = 0, T2 = 0 , W256[16] = {0}; + int j = 0; /* Initialize registers with the prev. intermediate value */ a = state_in[0]; @@ -791,7 +791,7 @@ void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2 /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; + s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ @@ -827,7 +827,7 @@ void sha256_Transform(const sha2_word32* state_in, const sha2_word32* data, sha2 #endif /* SHA2_UNROLL_TRANSFORM */ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; + unsigned int freespace = 0, usedspace = 0; if (len == 0) { /* Calling with no data is valid - we do nothing */ @@ -885,14 +885,14 @@ void sha256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { } void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { - unsigned int usedspace; + unsigned int usedspace = 0; /* If no digest buffer is passed, we don't bother doing this: */ if (digest != (sha2_byte*)0) { usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; /* Begin padding with a 1 bit: */ ((uint8_t*)context->buffer)[usedspace++] = 0x80; - + if (usedspace > SHA256_SHORT_BLOCK_LENGTH) { memzero(((uint8_t*)context->buffer) + usedspace, SHA256_BLOCK_LENGTH - usedspace); @@ -904,7 +904,7 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { #endif /* Do second-to-last transform: */ sha256_Transform(context->state, context->buffer, context->state); - + /* And prepare the last transform: */ usedspace = 0; } @@ -939,8 +939,8 @@ void sha256_Final(SHA256_CTX* context, sha2_byte digest[]) { } char *sha256_End(SHA256_CTX* context, char buffer[]) { - sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; - int i; + sha2_byte digest[SHA256_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; if (buffer != (char*)0) { sha256_Final(context, digest); @@ -959,14 +959,14 @@ char *sha256_End(SHA256_CTX* context, char buffer[]) { } void sha256_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA256_DIGEST_LENGTH]) { - SHA256_CTX context; + SHA256_CTX context = {0}; sha256_Init(&context); sha256_Update(&context, data, len); sha256_Final(&context, digest); } char* sha256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context; + SHA256_CTX context = {0}; sha256_Init(&context); sha256_Update(&context, data, len); @@ -1006,9 +1006,9 @@ void sha512_Init(SHA512_CTX* context) { j++ void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, W512[16]; - int j; + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, W512[16] = {0}; + int j = 0; /* Initialize registers with the prev. intermediate value */ a = state_in[0]; @@ -1061,9 +1061,9 @@ void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2 #else /* SHA2_UNROLL_TRANSFORM */ void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2_word64* state_out) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, T2, W512[16]; - int j; + sha2_word64 a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, s0 = 0, s1 = 0; + sha2_word64 T1 = 0, T2 = 0, W512[16] = {0}; + int j = 0; /* Initialize registers with the prev. intermediate value */ a = state_in[0]; @@ -1132,7 +1132,7 @@ void sha512_Transform(const sha2_word64* state_in, const sha2_word64* data, sha2 #endif /* SHA2_UNROLL_TRANSFORM */ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; + unsigned int freespace = 0, usedspace = 0; if (len == 0) { /* Calling with no data is valid - we do nothing */ @@ -1190,12 +1190,12 @@ void sha512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { } static void sha512_Last(SHA512_CTX* context) { - unsigned int usedspace; + unsigned int usedspace = 0; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; /* Begin padding with a 1 bit: */ ((uint8_t*)context->buffer)[usedspace++] = 0x80; - + if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { memzero(((uint8_t*)context->buffer) + usedspace, SHA512_BLOCK_LENGTH - usedspace); @@ -1248,8 +1248,8 @@ void sha512_Final(SHA512_CTX* context, sha2_byte digest[]) { } char *sha512_End(SHA512_CTX* context, char buffer[]) { - sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; - int i; + sha2_byte digest[SHA512_DIGEST_LENGTH] = {0}, *d = digest; + int i = 0; if (buffer != (char*)0) { sha512_Final(context, digest); @@ -1268,14 +1268,14 @@ char *sha512_End(SHA512_CTX* context, char buffer[]) { } void sha512_Raw(const sha2_byte* data, size_t len, uint8_t digest[SHA512_DIGEST_LENGTH]) { - SHA512_CTX context; + SHA512_CTX context = {0}; sha512_Init(&context); sha512_Update(&context, data, len); sha512_Final(&context, digest); } char* sha512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { - SHA512_CTX context; + SHA512_CTX context = {0}; sha512_Init(&context); sha512_Update(&context, data, len); diff --git a/Sources/VIZ/Base58.swift b/Sources/VIZ/Base58.swift deleted file mode 100644 index 74f8e27..0000000 --- a/Sources/VIZ/Base58.swift +++ /dev/null @@ -1,59 +0,0 @@ -/** - Base58 parser and encoder. - - author: Johan Nordberg - */ - -import Crypto -import Foundation - -internal extension Data { - /// Base58 encoding and decoding options. - struct Base58CheckOptions: OptionSet { - let rawValue: Int - /// Use graphene-style ripem160 checksum. - static let grapheneChecksum = Base58CheckOptions(rawValue: 1 << 0) - } - - /** - Creates a new data buffer from a Base58Check-encoded string. - - note: Returns nil if the check fails or if the string decodes to more than 128 bytes. - */ - init?(base58CheckEncoded str: String, options: Base58CheckOptions = []) { - let len = str.count - let data = UnsafeMutablePointer.allocate(capacity: len) - defer { data.deallocate() } - let res = str.withCString { (ptr: UnsafePointer) -> Int32 in - if options.contains(.grapheneChecksum) { - return base58gph_decode_check(ptr, data, Int32(len)) - } else { - return base58_decode_check(ptr, HASHER_SHA2D, data, Int32(len)) - } - } - guard res > 0 else { - return nil - } - self = Data(bytes: data, count: Int(res)) - } - - /** - Returns a Base58Check-encoded string. - - parameter graphene: Whether to encode with graphene-style ripem160 checksum or double-sha256. - - note: Returns nil for any data buffer larger than 128 bytes. - */ - func base58CheckEncodedString(options: Base58CheckOptions = []) -> String? { - let len = self.count * 2 - let str = UnsafeMutablePointer.allocate(capacity: len) - defer { str.deallocate() } - let res = self.withUnsafeBytes { (ptr: UnsafePointer) -> Int32 in - if options.contains(.grapheneChecksum) { - return base58gph_encode_check(ptr, Int32(self.count), str, Int32(len)) - } else { - return base58_encode_check(ptr, Int32(self.count), HASHER_SHA2D, str, Int32(len)) - } - } - guard res > 0 else { - return nil - } - return String(cString: str) - } -} diff --git a/Sources/VIZ/Extensions/Data+Base58Encoding.swift b/Sources/VIZ/Extensions/Data+Base58Encoding.swift new file mode 100644 index 0000000..eb20348 --- /dev/null +++ b/Sources/VIZ/Extensions/Data+Base58Encoding.swift @@ -0,0 +1,87 @@ +/// Base58 encoding and decoding extensions for the Data type. +/// - Author: Johan Nordberg + +import Crypto +import Foundation + +public extension Data { + /// Base58 encoding and decoding options. + enum Base58CheckType { + /// Use double-SHA256 checksum (Bitcoin-style). + case sha256d + /// Use RIPEMD160 checksum (Graphehe-style). + case ripemd160 + /// Use RIPEMD160 checksum with extra suffix (EOSIO-style). + case ripemd160Extra(_ extra: Data) + } + + /// Calculate checksum for data using given checksum type. + private static func checksum(for data: Data, using checksumType: Base58CheckType) -> Data { + let digest: Data + switch checksumType { + case .sha256d: + digest = data.sha256Digest.sha256Digest + case .ripemd160: + digest = data.ripemd160Digest + case let .ripemd160Extra(extra): + digest = (data + extra).ripemd160Digest + } + return digest.prefix(4) + } + + /// Creates a new data buffer from a Base58Check-encoded string. + /// - Parameter checksumType: Checksum to use when decoding data, defaults to the standard double-sha256. + /// - Note: Returns `nil` if decoding or the check fails. + init?(base58CheckEncoded str: String, _ checksumType: Base58CheckType = .sha256d) { + guard let decoded = Data(base58Encoded: str), decoded.count > 4 else { + return nil + } + let data = decoded.prefix(decoded.count - 4) + let checksum = decoded.suffix(4) + guard Self.checksum(for: data, using: checksumType) == checksum else { + return nil + } + self = data + } + + /// Creates a new data buffer from a Base58-encoded string. + /// - Note: Returns `nil` if decoding fails. + init?(base58Encoded str: String) { + let len: size_t = str.lengthOfBytes(using: .utf8) + let data = UnsafeMutablePointer.allocate(capacity: len) + defer { data.deallocate() } + let res = str.withCString { str -> Int in + base58_decode(str, data, len) + } + guard res > 0 else { + return nil + } + self = Data(bytes: data, count: res) + } + + /// Returns a Base58Check-encoded string. + /// - Parameter options: Options to use when encoding string. + /// - Note: Returns `nil` if data buffer is empty or null.. + func base58CheckEncodedString(_ checksumType: Base58CheckType = .sha256d) -> String? { + return (self + Self.checksum(for: self, using: checksumType)).base58EncodedString() + } + + /// Encode data into base58 format. + /// - Returns: Base58-encoded string or `nil` if encoding fails. + /// - Note: Returns `nil` if data buffer is empty or larger than 4kb. + func base58EncodedString() -> String? { + let strsize = self.count * 2 + let str = UnsafeMutablePointer.allocate(capacity: strsize) + defer { str.deallocate() } + let res = self.withUnsafeBytes { ptr -> Int in + guard !ptr.isEmpty, ptr.count <= 4000 else { + return 0 + } + return base58_encode(ptr.bufPtr, ptr.count, str, strsize) + } + guard res > 0 else { + return nil + } + return String(cString: str) + } +} diff --git a/Sources/VIZ/Extensions/Data+RIPEMD160.swift b/Sources/VIZ/Extensions/Data+RIPEMD160.swift new file mode 100644 index 0000000..9b2403f --- /dev/null +++ b/Sources/VIZ/Extensions/Data+RIPEMD160.swift @@ -0,0 +1,20 @@ +/// RIPEMD160 hash extension for the Data type. +/// - Author: Johan Nordberg + +import Crypto +import Foundation + +public extension Data { + var ripemd160Digest: Data { + var rv = Data(repeating: 0, count: Int(RIPEMD160_DIGEST_LENGTH)) + self.withUnsafeBytes { msg in + guard msg.baseAddress != nil else { + return + } + rv.withUnsafeMutableBytes { hash -> Void in + ripemd160(msg.bufPtr, UInt32(msg.count), hash.bufPtr) + } + } + return rv + } +} diff --git a/Sources/VIZ/Extensions/Data+SHA2.swift b/Sources/VIZ/Extensions/Data+SHA2.swift new file mode 100644 index 0000000..0adfabb --- /dev/null +++ b/Sources/VIZ/Extensions/Data+SHA2.swift @@ -0,0 +1,35 @@ +/// SHA2 hash extension for the Data type. +/// - Author: Johan Nordberg + +import Crypto +import Foundation + +public extension Data { + /// 32-byte SHA-256 digest of data. + var sha256Digest: Data { + var rv = Data(repeating: 0, count: Int(SHA256_DIGEST_LENGTH)) + self.withUnsafeBytes { msg in + guard msg.baseAddress != nil else { + return + } + rv.withUnsafeMutableBytes { hash -> Void in + sha256_Raw(msg.bufPtr, msg.count, hash.bufPtr) + } + } + return rv + } + + /// 64-byte SHA-512 digest of data. + var sha512Digest: Data { + var rv = Data(repeating: 0, count: Int(SHA512_DIGEST_LENGTH)) + self.withUnsafeBytes { msg in + guard msg.baseAddress != nil else { + return + } + rv.withUnsafeMutableBytes { hash -> Void in + sha512_Raw(msg.bufPtr, msg.count, hash.bufPtr) + } + } + return rv + } +} diff --git a/Sources/VIZ/PrivateKey.swift b/Sources/VIZ/PrivateKey.swift index aae147d..3885933 100644 --- a/Sources/VIZ/PrivateKey.swift +++ b/Sources/VIZ/PrivateKey.swift @@ -38,7 +38,7 @@ public struct PrivateKey: Equatable { guard let data = seed.data(using: .utf8) else { return nil } - self.secret = data.sha256Digest() + self.secret = data.sha256Digest } /// Sign a message. @@ -50,7 +50,7 @@ public struct PrivateKey: Equatable { if PrivateKey.determenisticSignatures { ndata[0] += 1 } else { - ndata = Random.bytes(count: 32) + ndata = Data.random(32) } result = try Secp256k1.shared.sign(message: message, secretKey: self.secret, ndata: ndata) } while (!isCanonicalSignature(result.0)) diff --git a/Sources/VIZ/PublicKey.swift b/Sources/VIZ/PublicKey.swift index ccab63a..a3d0914 100644 --- a/Sources/VIZ/PublicKey.swift +++ b/Sources/VIZ/PublicKey.swift @@ -40,7 +40,7 @@ public struct PublicKey: Equatable { guard key.count > 0 else { return nil } - guard let keyData = Data(base58CheckEncoded: String(key), options: .grapheneChecksum) else { + guard let keyData = Data(base58CheckEncoded: String(key), .ripemd160) else { return nil } self.prefix = AddressPrefix(String(prefix)) @@ -49,7 +49,7 @@ public struct PublicKey: Equatable { /// Public key address string. public var address: String { - return String(self.prefix) + self.key.base58CheckEncodedString(options: .grapheneChecksum)! + return String(self.prefix) + self.key.base58CheckEncodedString(.ripemd160)! } } diff --git a/Sources/VIZ/Random.swift b/Sources/VIZ/Random.swift deleted file mode 100644 index c9438d7..0000000 --- a/Sources/VIZ/Random.swift +++ /dev/null @@ -1,39 +0,0 @@ -/// Cryptographically secure random number generation. -/// - Author: Johan Nordberg - -import Foundation - -#if !os(Linux) - import Security -#else - import Glibc -#endif - -/// A cryptographically secure number random generator. -internal struct Random { - /// Get random bytes. - /// - Parameter count: How many bytes to generate. - static func bytes(count: Int) -> Data { - var rv = Data(count: count) - #if os(Linux) - guard let file = fopen("/dev/urandom", "r") else { - fatalError("Unable to open /dev/urandom for reading.") - } - defer { fclose(file) } - let bytesRead = rv.withUnsafeMutableBytes { - fread($0, 1, count, file) - } - guard bytesRead == count else { - fatalError("Unable to read from /dev/urandom.") - } - #else - let result = rv.withUnsafeMutableBytes { - SecRandomCopyBytes(kSecRandomDefault, count, $0) - } - guard result == errSecSuccess else { - fatalError("Unable to generate random data.") - } - #endif - return rv - } -} diff --git a/Sources/VIZ/Sha2.swift b/Sources/VIZ/Sha2.swift deleted file mode 100644 index 478215e..0000000 --- a/Sources/VIZ/Sha2.swift +++ /dev/null @@ -1,18 +0,0 @@ -/// Sha2 bindings. -/// - Author: Johan Nordberg - -import Crypto -import Foundation - -internal extension Data { - /// Return a SHA2-256 hash of the data. - func sha256Digest() -> Data { - let buf = UnsafeMutablePointer.allocate(capacity: 32) - self.withUnsafeBytes { - hasher_Raw(HASHER_SHA2, $0, self.count, buf) - } - return Data(bytesNoCopy: buf, count: 32, deallocator: .custom({ ptr, _ in - ptr.deallocate() - })) - } -} diff --git a/Sources/VIZ/Transaction.swift b/Sources/VIZ/Transaction.swift index abb7dd3..f427df6 100644 --- a/Sources/VIZ/Transaction.swift +++ b/Sources/VIZ/Transaction.swift @@ -55,8 +55,7 @@ public struct Transaction: _Transaction { public func digest(forChain chain: ChainId = .mainNet) throws -> Data { var data = chain.data data.append(try VIZEncoder.encode(self)) -// print(data.hexEncodedString()) - return data.sha256Digest() + return data.sha256Digest } } diff --git a/Tests/UnitTests/Base58.swift b/Tests/UnitTests/Base58.swift index 8c29b45..aba1b15 100644 --- a/Tests/UnitTests/Base58.swift +++ b/Tests/UnitTests/Base58.swift @@ -63,17 +63,17 @@ let base64_base58_pairs = [ class Base58Test: XCTestCase { func testDecode() { for (b64, b58, graphene) in base64_base58_pairs { - let options: Data.Base58CheckOptions = graphene ? [.grapheneChecksum] : [] - let data = Data(base58CheckEncoded: b58, options: options) + let options: Data.Base58CheckType = graphene ? .ripemd160 : .sha256d + let data = Data(base58CheckEncoded: b58, options) XCTAssertEqual(data?.base64EncodedString(), b64) } } func testEncode() { for (b64, b58, graphene) in base64_base58_pairs { - let options: Data.Base58CheckOptions = graphene ? [.grapheneChecksum] : [] + let options: Data.Base58CheckType = graphene ? .ripemd160 : .sha256d let data = Data(base64Encoded: b64)! - XCTAssertEqual(data.base58CheckEncodedString(options: options), b58) + XCTAssertEqual(data.base58CheckEncodedString(options), b58) } } } diff --git a/Tests/UnitTests/Sha2.swift b/Tests/UnitTests/Sha2.swift index cc5be89..31cd9ec 100644 --- a/Tests/UnitTests/Sha2.swift +++ b/Tests/UnitTests/Sha2.swift @@ -4,6 +4,6 @@ import XCTest class Sha2Test: XCTestCase { func testDigest() { let data = Data(base64Encoded: "A4fYIELZNEcAjf4q92IGih5T/zlKW/j2igRfpkK5nqXR")! - XCTAssertEqual(data.sha256Digest(), Data(base64Encoded: "nxseRPD/eP7rVE0ceWhzRvPNyfbiNlPKKuS6f+6cHUY=")) + XCTAssertEqual(data.sha256Digest, Data(base64Encoded: "nxseRPD/eP7rVE0ceWhzRvPNyfbiNlPKKuS6f+6cHUY=")) } }