| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- // Copyright (c) 2014-2018, The Monero Project
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are met:
- //
- // 1. Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // 2. Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // 3. Neither the name of the copyright holder nor the names of its contributors
- // may be used to endorse or promote products derived from this software
- // without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- // POSSIBILITY OF SUCH DAMAGE.
- //
- // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote
- // developers
- #if USE_MONERO
- #include "base58.h"
- #include <assert.h>
- #include <stdbool.h>
- #include <string.h>
- #include <sys/types.h>
- #include "../base58.h"
- #include "../byte_order.h"
- #include "int-util.h"
- #include "../sha2.h"
- const size_t alphabet_size = 58; // sizeof(b58digits_ordered) - 1;
- const size_t full_encoded_block_size = 11;
- const size_t encoded_block_sizes[] = {
- 0, 2, 3, 5, 6, 7, 9, 10, full_encoded_block_size};
- const size_t full_block_size =
- sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1;
- const size_t addr_checksum_size = 4;
- const size_t max_bin_data_size = 72;
- const int decoded_block_sizes[] = {0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8};
- #define reverse_alphabet(letter) ((int8_t)b58digits_map[(int)letter])
- uint64_t uint_8be_to_64(const uint8_t *data, size_t size) {
- assert(1 <= size && size <= sizeof(uint64_t));
- uint64_t res = 0;
- switch (9 - size) {
- case 1:
- res |= *data++; /* FALLTHRU */
- case 2:
- res <<= 8;
- res |= *data++; /* FALLTHRU */
- case 3:
- res <<= 8;
- res |= *data++; /* FALLTHRU */
- case 4:
- res <<= 8;
- res |= *data++; /* FALLTHRU */
- case 5:
- res <<= 8;
- res |= *data++; /* FALLTHRU */
- case 6:
- res <<= 8;
- res |= *data++; /* FALLTHRU */
- case 7:
- res <<= 8;
- res |= *data++; /* FALLTHRU */
- case 8:
- res <<= 8;
- res |= *data;
- break;
- default:
- assert(false);
- }
- return res;
- }
- void uint_64_to_8be(uint64_t num, size_t size, uint8_t *data) {
- assert(1 <= size && size <= sizeof(uint64_t));
- #if BYTE_ORDER == LITTLE_ENDIAN
- uint64_t num_be = SWAP64(num);
- #else
- uint64_t num_be = num;
- #endif
- memcpy(data, (uint8_t *)(&num_be) + sizeof(uint64_t) - size, size);
- }
- void encode_block(const char *block, size_t size, char *res) {
- assert(1 <= size && size <= full_block_size);
- uint64_t num = uint_8be_to_64((uint8_t *)(block), size);
- int i = ((int)(encoded_block_sizes[size])) - 1;
- while (0 <= i) {
- uint64_t remainder = num % alphabet_size;
- num /= alphabet_size;
- res[i] = b58digits_ordered[remainder];
- --i;
- }
- }
- bool decode_block(const char *block, size_t size, char *res) {
- assert(1 <= size && size <= full_encoded_block_size);
- int res_size = decoded_block_sizes[size];
- if (res_size <= 0) {
- return false; // Invalid block size
- }
- uint64_t res_num = 0;
- uint64_t order = 1;
- for (size_t i = size - 1; i < size; --i) {
- if (block[i] & 0x80) {
- return false; // Invalid symbol
- }
- int digit = reverse_alphabet(block[i]);
- if (digit < 0) {
- return false; // Invalid symbol
- }
- uint64_t product_hi = 0;
- uint64_t tmp = res_num + mul128(order, (uint64_t)digit, &product_hi);
- if (tmp < res_num || 0 != product_hi) {
- return false; // Overflow
- }
- res_num = tmp;
- // The original code comment for the order multiplication says
- // "Never overflows, 58^10 < 2^64"
- // This is incorrect since it overflows on the 11th iteration
- // However, there is no negative impact since the result is unused
- order *= alphabet_size;
- }
- if ((size_t)res_size < full_block_size &&
- (UINT64_C(1) << (8 * res_size)) <= res_num)
- return false; // Overflow
- uint_64_to_8be(res_num, res_size, (uint8_t *)(res));
- return true;
- }
- bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data,
- size_t binsz) {
- if (binsz == 0) {
- if (b58sz) {
- *b58sz = 0;
- }
- return true;
- }
- const char *data_bin = data;
- size_t full_block_count = binsz / full_block_size;
- size_t last_block_size = binsz % full_block_size;
- size_t res_size = full_block_count * full_encoded_block_size +
- encoded_block_sizes[last_block_size];
- if (b58sz) {
- if (res_size > *b58sz) {
- return false;
- }
- *b58sz = res_size;
- }
- for (size_t i = 0; i < full_block_count; ++i) {
- encode_block(data_bin + i * full_block_size, full_block_size,
- b58 + i * full_encoded_block_size);
- }
- if (0 < last_block_size) {
- encode_block(data_bin + full_block_count * full_block_size, last_block_size,
- b58 + full_block_count * full_encoded_block_size);
- }
- return true;
- }
- bool xmr_base58_decode(const char *b58, size_t b58sz, void *data,
- size_t *binsz) {
- if (b58sz == 0) {
- *binsz = 0;
- return true;
- }
- size_t full_block_count = b58sz / full_encoded_block_size;
- size_t last_block_size = b58sz % full_encoded_block_size;
- int last_block_decoded_size = decoded_block_sizes[last_block_size];
- if (last_block_decoded_size < 0) {
- *binsz = 0;
- return false; // Invalid enc length
- }
- size_t data_size =
- full_block_count * full_block_size + last_block_decoded_size;
- if (*binsz < data_size) {
- *binsz = 0;
- return false;
- }
- char *data_bin = data;
- for (size_t i = 0; i < full_block_count; ++i) {
- if (!decode_block(b58 + i * full_encoded_block_size,
- full_encoded_block_size,
- data_bin + i * full_block_size)) {
- *binsz = 0;
- return false;
- }
- }
- if (0 < last_block_size) {
- if (!decode_block(b58 + full_block_count * full_encoded_block_size,
- last_block_size,
- data_bin + full_block_count * full_block_size)) {
- *binsz = 0;
- return false;
- }
- }
- *binsz = data_size;
- return true;
- }
- int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data,
- size_t binsz, char *b58, size_t b58sz) {
- if (binsz > max_bin_data_size || tag > 127) { // tag varint
- return false;
- }
- size_t b58size = b58sz;
- uint8_t buf[(binsz + 1) + HASHER_DIGEST_LENGTH];
- memset(buf, 0, sizeof(buf));
- uint8_t *hash = buf + binsz + 1;
- buf[0] = (uint8_t)tag;
- memcpy(buf + 1, data, binsz);
- hasher_Raw(HASHER_SHA3K, buf, binsz + 1, hash);
- bool r =
- xmr_base58_encode(b58, &b58size, buf, binsz + 1 + addr_checksum_size);
- return (int)(!r ? 0 : b58size);
- }
- int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag,
- void *data, size_t datalen) {
- size_t buflen = 1 + max_bin_data_size + addr_checksum_size;
- uint8_t buf[buflen];
- memset(buf, 0, sizeof(buf));
- uint8_t hash[HASHER_DIGEST_LENGTH] = {0};
- if (!xmr_base58_decode(addr, sz, buf, &buflen)) {
- return 0;
- }
- if (buflen <= addr_checksum_size + 1) {
- return 0;
- }
- size_t res_size = buflen - addr_checksum_size - 1;
- if (datalen < res_size) {
- return 0;
- }
- hasher_Raw(HASHER_SHA3K, buf, buflen - addr_checksum_size, hash);
- if (memcmp(hash, buf + buflen - addr_checksum_size, addr_checksum_size) !=
- 0) {
- return 0;
- }
- *tag = buf[0];
- if (*tag > 127) {
- return false; // varint
- }
- memcpy(data, buf + 1, res_size);
- return (int)res_size;
- }
- #endif // USE_MONERO
|