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

Commit

Permalink
xmr: monero crypto implemented, tests
Browse files Browse the repository at this point in the history
- basic monero crypto in ed25519 (ge, fe, sc)
- monero specific functions
- serialization routines
- memory optimized range proof
- xmr base58 shares tables with original base58
  • Loading branch information
ph4r05 committed Jul 21, 2018
1 parent a7463bc commit 14e27a0
Show file tree
Hide file tree
Showing 20 changed files with 2,859 additions and 5 deletions.
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
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

0 comments on commit 14e27a0

Please sign in to comment.