Skip to content
This repository has been archived by the owner on Nov 16, 2021. It is now read-only.

xmr: monero crypto functions, tests #162

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ CFLAGS += -I.
CFLAGS += -DVALGRIND=$(VALGRIND)
CFLAGS += -DUSE_ETHEREUM=1
CFLAGS += -DUSE_GRAPHENE=1
CFLAGS += -DUSE_NEM=1
CFLAGS += -DUSE_KECCAK=1
CFLAGS += -DUSE_MONERO=1
CFLAGS += -DUSE_NEM=1
CFLAGS += -DUSE_CARDANO=1
CFLAGS += $(shell pkg-config --cflags openssl)

Expand All @@ -50,6 +51,11 @@ SRCS += aes/aescrypt.c aes/aeskey.c aes/aestab.c aes/aes_modes.c
SRCS += ed25519-donna/curve25519-donna-32bit.c ed25519-donna/curve25519-donna-helpers.c ed25519-donna/modm-donna-32bit.c
SRCS += ed25519-donna/ed25519-donna-basepoint-table.c ed25519-donna/ed25519-donna-32bit-tables.c ed25519-donna/ed25519-donna-impl-base.c
SRCS += ed25519-donna/ed25519.c ed25519-donna/curve25519-donna-scalarmult-base.c ed25519-donna/ed25519-sha3.c ed25519-donna/ed25519-keccak.c
SRCS += monero/base58.c
SRCS += monero/serialize.c
SRCS += monero/crypto.c
SRCS += monero/xmr.c
SRCS += monero/range_proof.c
SRCS += blake256.c
SRCS += blake2b.c blake2s.c
SRCS += groestl.c
Expand All @@ -74,7 +80,7 @@ tests: tests/test_check tests/test_openssl tests/test_speed tests/libtrezor-cryp
tests/aestst: aes/aestst.o aes/aescrypt.o aes/aeskey.o aes/aestab.o
$(CC) $^ -o $@

tests/test_check.o: tests/test_check_cardano.h tests/test_check_cashaddr.h tests/test_check_segwit.h
tests/test_check.o: tests/test_check_cardano.h tests/test_check_monero.h tests/test_check_cashaddr.h tests/test_check_segwit.h

tests/test_check: tests/test_check.o $(OBJS)
$(CC) tests/test_check.o $(OBJS) $(TESTLIBS) -o tests/test_check
Expand Down
5 changes: 2 additions & 3 deletions base58.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
#include "ripemd160.h"
#include "memzero.h"

static const int8_t b58digits_map[] = {
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,
Expand Down Expand Up @@ -148,8 +149,6 @@ int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *
return binc[0];
}

static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
Expand Down
3 changes: 3 additions & 0 deletions base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#include "hasher.h"
#include "options.h"

extern const char b58digits_ordered[];
extern const int8_t b58digits_map[];

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);

Expand Down
5 changes: 5 additions & 0 deletions ed25519-donna/ed25519-donna.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
Bo-Yin Yang
*/

#ifndef ED25519_DONNA_H
#define ED25519_DONNA_H

#include "ed25519-donna-portable.h"

#include "curve25519-donna-32bit.h"
Expand Down Expand Up @@ -45,3 +48,5 @@ typedef struct ge25519_pniels_t {
#include "ed25519-donna-32bit-tables.h"

#include "ed25519-donna-impl-base.h"

#endif
20 changes: 20 additions & 0 deletions hasher.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ void hasher_Init(Hasher *hasher, HasherType type) {
case HASHER_SHA2D:
sha256_Init(&hasher->ctx.sha2);
break;
case HASHER_SHA3:
#if USE_KECCAK
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not needed?

case HASHER_SHA3K:
#endif
sha3_256_Init(&hasher->ctx.sha3);
break;
case HASHER_BLAKE:
case HASHER_BLAKED:
blake256_Init(&hasher->ctx.blake);
Expand Down Expand Up @@ -62,6 +68,12 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) {
case HASHER_SHA2D:
sha256_Update(&hasher->ctx.sha2, data, length);
break;
case HASHER_SHA3:
#if USE_KECCAK
case HASHER_SHA3K:
#endif
sha3_Update(&hasher->ctx.sha3, data, length);
break;
case HASHER_BLAKE:
case HASHER_BLAKED:
blake256_Update(&hasher->ctx.blake, data, length);
Expand All @@ -87,6 +99,14 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) {
sha256_Final(&hasher->ctx.sha2, hash);
hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_SHA3:
sha3_Final(&hasher->ctx.sha3, hash);
break;
#if USE_KECCAK
case HASHER_SHA3K:
keccak_Final(&hasher->ctx.sha3, hash);
break;
#endif
case HASHER_BLAKE:
blake256_Final(&hasher->ctx.blake, hash);
break;
Expand Down
8 changes: 8 additions & 0 deletions hasher.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <stdint.h>

#include "sha2.h"
#include "sha3.h"
#include "blake256.h"
#include "groestl.h"
#include "blake2b.h"
Expand All @@ -42,6 +43,12 @@ typedef enum {

HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */

HASHER_SHA3,

#if USE_KECCAK
HASHER_SHA3K,
#endif

HASHER_OVERWINTER_PREVOUTS,
HASHER_OVERWINTER_SEQUENCE,
HASHER_OVERWINTER_OUTPUTS,
Expand All @@ -53,6 +60,7 @@ typedef struct {

union {
SHA256_CTX sha2;
SHA3_CTX sha3;
BLAKE256_CTX blake;
GROESTL512_CTX groestl;
BLAKE2B_CTX blake2b;
Expand Down
243 changes: 243 additions & 0 deletions monero/base58.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
// 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

#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include "base58.h"
#include "int-util.h"
#include "sha2.h"
#include "../base58.h"

const size_t alphabet_size = 58; // sizeof(b58digits_ordered) - 1;
const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11};
const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1;
const size_t full_encoded_block_size = 11; // encoded_block_sizes[full_block_size];
const size_t addr_checksum_size = 4;
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));

uint64_t num_be = SWAP64(num);
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)
{
int digit = reverse_alphabet(block[i]);
if (digit < 0)
return false; // Invalid symbol

uint64_t product_hi;
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;
order *= alphabet_size; // Never overflows, 58^10 < 2^64
}

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)
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))
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))
return false;
}

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 > 128 || tag > 127) { // tag varint
return false;
}

size_t b58size = b58sz;
uint8_t buf[binsz + 1 + HASHER_DIGEST_LENGTH];
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 + 64 + addr_checksum_size;
uint8_t buf[buflen];
uint8_t hash[HASHER_DIGEST_LENGTH];

if (!xmr_base58_decode(addr, sz, buf, &buflen)){
return 0;
}

size_t res_size = buflen - addr_checksum_size - 1;
if (datalen < res_size){
return 0;
}

if (buflen <= addr_checksum_size+1) {
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;
}
Loading