Browse Source

xmr: monero crypto implemented, tests

master
Dusan Klinec 1 year ago
parent
commit
775871d866
No account linked to committer's email address

+ 6
- 1
Makefile View File

@@ -51,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 += ed25519-donna/ge25519.c
SRCS += monero/base58.c
SRCS += monero/serialize.c
SRCS += monero/xmr.c
SRCS += monero/range_proof.c
SRCS += blake256.c
SRCS += blake2b.c blake2s.c
SRCS += groestl.c
@@ -75,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

+ 2
- 3
base58.c View File

@@ -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,
@@ -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;

+ 3
- 0
base58.h View File

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


+ 378
- 0
ed25519-donna/ge25519.c View File

@@ -0,0 +1,378 @@
//
// Created by Dusan Klinec on 29/04/2018.
//

#include <assert.h>
#include "ge25519.h"

static const uint32_t reduce_mask_25 = (1 << 25) - 1;
static const uint32_t reduce_mask_26 = (1 << 26) - 1;

/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */
/* d = -121665 / 121666 */
static const bignum25519 ALIGN(16) fe_d = {
0x35978a3, 0x0d37284, 0x3156ebd, 0x06a0a0e, 0x001c029, 0x179e898, 0x3a03cbb, 0x1ce7198, 0x2e2b6ff, 0x1480db3}; /* d */
static const bignum25519 ALIGN(16) fe_sqrtm1 = {
0x20ea0b0, 0x186c9d2, 0x08f189d, 0x035697f, 0x0bd0c60, 0x1fbd7a7, 0x2804c9e, 0x1e16569, 0x004fc1d, 0x0ae0c92}; /* sqrt(-1) */
//static const bignum25519 ALIGN(16) fe_d2 = {
// 0x2b2f159, 0x1a6e509, 0x22add7a, 0x0d4141d, 0x0038052, 0x0f3d130, 0x3407977, 0x19ce331, 0x1c56dff, 0x0901b67}; /* 2 * d */

/* A = 2 * (1 - d) / (1 + d) = 486662 */
static const bignum25519 ALIGN(16) fe_ma2 = {
0x33de3c9, 0x1fff236, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A^2 */
static const bignum25519 ALIGN(16) fe_ma = {
0x3f892e7, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff}; /* -A */
static const bignum25519 ALIGN(16) fe_fffb1 = {
0x1e3bdff, 0x025a2b3, 0x18e5bab, 0x0ba36ac, 0x0b9afed, 0x004e61c, 0x31d645f, 0x09d1bea, 0x102529e, 0x0063810}; /* sqrt(-2 * A * (A + 2)) */
static const bignum25519 ALIGN(16) fe_fffb2 = {
0x383650d, 0x066df27, 0x10405a4, 0x1cfdd48, 0x2b887f2, 0x1e9a041, 0x1d7241f, 0x0612dc5, 0x35fba5d, 0x0cbe787}; /* sqrt(2 * A * (A + 2)) */
static const bignum25519 ALIGN(16) fe_fffb3 = {
0x0cfd387, 0x1209e3a, 0x3bad4fc, 0x18ad34d, 0x2ff6c02, 0x0f25d12, 0x15cdfe0, 0x0e208ed, 0x32eb3df, 0x062d7bb}; /* sqrt(-sqrt(-1) * A * (A + 2)) */
static const bignum25519 ALIGN(16) fe_fffb4 = {
0x2b39186, 0x14640ed, 0x14930a7, 0x04509fa, 0x3b91bf0, 0x0f7432e, 0x07a443f, 0x17f24d8, 0x031067d, 0x0690fcc}; /* sqrt(sqrt(-1) * A * (A + 2)) */

void curve25519_set(bignum25519 r, uint32_t x){
r[0] = x & reduce_mask_26; x >>= 26;
r[1] = x & reduce_mask_25;
r[2] = 0;
r[3] = 0;
r[4] = 0;
r[5] = 0;
r[6] = 0;
r[7] = 0;
r[8] = 0;
r[9] = 0;
}

void curve25519_set_d(bignum25519 r){
curve25519_copy(r, ge25519_ecd);
}

void curve25519_set_2d(bignum25519 r){
curve25519_copy(r, ge25519_ec2d);
}

void curve25519_set_sqrtneg1(bignum25519 r){
curve25519_copy(r, ge25519_sqrtneg1);
}

int curve25519_isnegative(const bignum25519 f) {
unsigned char s[32];
curve25519_contract(s, f);
return s[0] & 1;
}

int curve25519_isnonzero(const bignum25519 f) {
unsigned char s[32];
curve25519_contract(s, f);
return ((((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] |
s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] |
s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] |
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1) & 0x1;
}

void curve25519_reduce(bignum25519 out, const bignum25519 in) {
uint32_t c;
out[0] = in[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;
out[1] = in[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;
out[2] = in[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;
out[3] = in[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;
out[4] = in[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26;
out[5] = in[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25;
out[6] = in[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26;
out[7] = in[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25;
out[8] = in[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26;
out[9] = in[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25;
out[0] += 19 * c;
}

static void curve25519_divpowm1(bignum25519 r, const bignum25519 u, const bignum25519 v) {
bignum25519 v3={0}, uv7={0}, t0={0}, t1={0}, t2={0};
int i;

curve25519_square(v3, v);
curve25519_mul(v3, v3, v); /* v3 = v^3 */
curve25519_square(uv7, v3);
curve25519_mul(uv7, uv7, v);
curve25519_mul(uv7, uv7, u); /* uv7 = uv^7 */

/*fe_pow22523(uv7, uv7);*/
/* From fe_pow22523.c */

curve25519_square(t0, uv7);
curve25519_square(t1, t0);
curve25519_square(t1, t1);
curve25519_mul(t1, uv7, t1);
curve25519_mul(t0, t0, t1);
curve25519_square(t0, t0);
curve25519_mul(t0, t1, t0);
curve25519_square(t1, t0);
for (i = 0; i < 4; ++i) {
curve25519_square(t1, t1);
}
curve25519_mul(t0, t1, t0);
curve25519_square(t1, t0);
for (i = 0; i < 9; ++i) {
curve25519_square(t1, t1);
}
curve25519_mul(t1, t1, t0);
curve25519_square(t2, t1);
for (i = 0; i < 19; ++i) {
curve25519_square(t2, t2);
}
curve25519_mul(t1, t2, t1);
for (i = 0; i < 10; ++i) {
curve25519_square(t1, t1);
}
curve25519_mul(t0, t1, t0);
curve25519_square(t1, t0);
for (i = 0; i < 49; ++i) {
curve25519_square(t1, t1);
}
curve25519_mul(t1, t1, t0);
curve25519_square(t2, t1);
for (i = 0; i < 99; ++i) {
curve25519_square(t2, t2);
}
curve25519_mul(t1, t2, t1);
for (i = 0; i < 50; ++i) {
curve25519_square(t1, t1);
}
curve25519_mul(t0, t1, t0);
curve25519_square(t0, t0);
curve25519_square(t0, t0);
curve25519_mul(t0, t0, uv7);

/* End fe_pow22523.c */
/* t0 = (uv^7)^((q-5)/8) */
curve25519_mul(t0, t0, v3);
curve25519_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */
}

void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]) {
uint32_t x0,x1,x2,x3,x4,x5,x6,x7;
#define F(s) \
((((uint32_t)in[s + 0]) ) | \
(((uint32_t)in[s + 1]) << 8) | \
(((uint32_t)in[s + 2]) << 16) | \
(((uint32_t)in[s + 3]) << 24))
x0 = F(0);
x1 = F(4);
x2 = F(8);
x3 = F(12);
x4 = F(16);
x5 = F(20);
x6 = F(24);
x7 = F(28);
#undef F

out[0] = ( x0 ) & reduce_mask_26;
out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & reduce_mask_25;
out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & reduce_mask_26;
out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & reduce_mask_25;
out[4] = (( x3) >> 6) & reduce_mask_26;
out[5] = ( x4 ) & reduce_mask_25;
out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & reduce_mask_26;
out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & reduce_mask_25;
out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & reduce_mask_26;
out[9] = (( x7) >> 6); // & reduce_mask_25; /* ignore the top bit */
out[0] += 19 * (out[9] >> 25);
out[9] &= reduce_mask_25;
}

int ge25519_check(const ge25519 *r){
/* return (z % q != 0 and
x * y % q == z * t % q and
(y * y - x * x - z * z - ed25519.d * t * t) % q == 0)
*/

bignum25519 z={0}, lhs={0}, rhs={0}, tmp={0}, res={0};
curve25519_reduce(z, r->z);

curve25519_mul(lhs, r->x, r->y);
curve25519_mul(rhs, r->z, r->t);
curve25519_sub_reduce(lhs, lhs, rhs);

curve25519_square(res, r->y);
curve25519_square(tmp, r->x);
curve25519_sub_reduce(res, res, tmp);
curve25519_square(tmp, r->z);
curve25519_sub_reduce(res, res, tmp);
curve25519_square(tmp, r->t);
curve25519_mul(tmp, tmp, ge25519_ecd);
curve25519_sub_reduce(res, res, tmp);

const int c1 = curve25519_isnonzero(z);
const int c2 = curve25519_isnonzero(lhs);
const int c3 = curve25519_isnonzero(res);
return c1 & (c2^0x1) & (c3^0x1);
}

int ge25519_eq(const ge25519 *a, const ge25519 *b){
int eq = 1;
bignum25519 t1={0}, t2={0};

eq &= ge25519_check(a);
eq &= ge25519_check(b);

curve25519_mul(t1, a->x, b->z);
curve25519_mul(t2, b->x, a->z);
curve25519_sub_reduce(t1, t1, t2);
eq &= curve25519_isnonzero(t1) ^ 1;

curve25519_mul(t1, a->y, b->z);
curve25519_mul(t2, b->y, a->z);
curve25519_sub_reduce(t1, t1, t2);
eq &= curve25519_isnonzero(t1) ^ 1;

return eq;
}

void ge25519_copy(ge25519 *dst, const ge25519 *src){
curve25519_copy(dst->x, src->x);
curve25519_copy(dst->y, src->y);
curve25519_copy(dst->z, src->z);
curve25519_copy(dst->t, src->t);
}

void ge25519_set_base(ge25519 *r){
ge25519_copy(r, &ge25519_basepoint);
}

void ge25519_mul8(ge25519 *r, const ge25519 *t) {
ge25519_double_partial(r, t);
ge25519_double_partial(r, r);
ge25519_double(r, r);
}

void ge25519_neg_partial(ge25519 *r){
curve25519_neg(r->x, r->x);
}

void ge25519_neg_full(ge25519 *r){
curve25519_neg(r->x, r->x);
curve25519_neg(r->t, r->t);
}

void ge25519_reduce(ge25519 *r, const ge25519 *t){
curve25519_reduce(r->x, t->x);
curve25519_reduce(r->y, t->y);
curve25519_reduce(r->z, t->z);
curve25519_reduce(r->t, t->t);
}

void ge25519_norm(ge25519 *r, const ge25519 * t){
bignum25519 zinv;
curve25519_recip(zinv, t->z);
curve25519_mul(r->x, t->x, zinv);
curve25519_mul(r->y, t->y, zinv);
curve25519_mul(r->t, r->x, r->y);
curve25519_set(r->z, 1);
}

void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q, unsigned char signbit) {
ge25519_pniels P_ni;
ge25519_p1p1 P_11;

ge25519_full_to_pniels(&P_ni, q);
ge25519_pnielsadd_p1p1(&P_11, p, &P_ni, signbit);
ge25519_p1p1_to_full(r, &P_11);
}

void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s){
bignum25519 u={0}, v={0}, w={0}, x={0}, y={0}, z={0};
unsigned char sign;

curve25519_expand_reduce(u, s);

curve25519_square(v, u);
curve25519_add_reduce(v, v, v); /* 2 * u^2 */
curve25519_set(w, 1);
curve25519_add_reduce(w, v, w); /* w = 2 * u^2 + 1 */

curve25519_square(x, w); /* w^2 */
curve25519_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */
curve25519_add_reduce(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */

curve25519_divpowm1(r->x, w, x); /* (w / x)^(m + 1) */
curve25519_square(y, r->x);
curve25519_mul(x, y, x);
curve25519_sub_reduce(y, w, x);
curve25519_copy(z, fe_ma);

if (curve25519_isnonzero(y)) {
curve25519_add_reduce(y, w, x);
if (curve25519_isnonzero(y)) {
goto negative;
} else {
curve25519_mul(r->x, r->x, fe_fffb1);
}
} else {
curve25519_mul(r->x, r->x, fe_fffb2);
}
curve25519_mul(r->x, r->x, u); /* u * sqrt(2 * A * (A + 2) * w / x) */
curve25519_mul(z, z, v); /* -2 * A * u^2 */
sign = 0;
goto setsign;
negative:
curve25519_mul(x, x, fe_sqrtm1);
curve25519_sub_reduce(y, w, x);
if (curve25519_isnonzero(y)) {
assert((curve25519_add_reduce(y, w, x), !curve25519_isnonzero(y)));
curve25519_mul(r->x, r->x, fe_fffb3);
} else {
curve25519_mul(r->x, r->x, fe_fffb4);
}
/* r->x = sqrt(A * (A + 2) * w / x) */
/* z = -A */
sign = 1;
setsign:
if (curve25519_isnegative(r->x) != sign) {
assert(curve25519_isnonzero(r->x));
curve25519_neg(r->x, r->x);
}
curve25519_add_reduce(r->z, z, w);
curve25519_sub_reduce(r->y, z, w);
curve25519_mul(r->x, r->x, r->z);

// Partial form, saving from T coord computation .
// Later is mul8 discarding T anyway.
// rt = ((rx * ry % q) * inv(rz)) % q
// curve25519_mul(x, r->x, r->y);
// curve25519_recip(z, r->z);
// curve25519_mul(r->t, x, z);

#if !defined(NDEBUG)
{
bignum25519 check_x={0}, check_y={0}, check_iz={0}, check_v={0};
curve25519_recip(check_iz, r->z);
curve25519_mul(check_x, r->x, check_iz);
curve25519_mul(check_y, r->y, check_iz);
curve25519_square(check_x, check_x);
curve25519_square(check_y, check_y);
curve25519_mul(check_v, check_x, check_y);
curve25519_mul(check_v, fe_d, check_v);
curve25519_add_reduce(check_v, check_v, check_x);
curve25519_sub_reduce(check_v, check_v, check_y);
curve25519_set(check_x, 1);
curve25519_add_reduce(check_v, check_v, check_x);
assert(!curve25519_isnonzero(check_v));
}
#endif
}

int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s){
int res = ge25519_unpack_negative_vartime(r, s);
ge25519_neg_full(r);
return res;
}

void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s){
ge25519_scalarmult_base_niels(r, ge25519_niels_base_multiples, s);
ge25519_norm(r, r);
}

void ge25519_scalarmult_wrapper(ge25519 *r, const ge25519 *P, const bignum256modm a){
ge25519_scalarmult(r, P, a);
ge25519_norm(r, r);
}

+ 77
- 0
ed25519-donna/ge25519.h View File

@@ -0,0 +1,77 @@
//
// Created by Dusan Klinec on 29/04/2018.
//

#ifndef GE25519_H
#define GE25519_H

#include <stdint.h>
#include "ed25519-donna.h"

/* uint32_t to Zmod(2^255-19) */
void curve25519_set(bignum25519 r, uint32_t x);

/* set d */
void curve25519_set_d(bignum25519 r);

/* set 2d */
void curve25519_set_2d(bignum25519 r);

/* set sqrt(-1) */
void curve25519_set_sqrtneg1(bignum25519 r);

/* constant time Zmod(2^255-19) negative test */
int curve25519_isnegative(const bignum25519 f);

/* constant time Zmod(2^255-19) non-zero test */
int curve25519_isnonzero(const bignum25519 f);

/* reduce Zmod(2^255-19) */
void curve25519_reduce(bignum25519 r, const bignum25519 in);

/* Zmod(2^255-19) from byte array to bignum25519 expansion with modular reduction */
void curve25519_expand_reduce(bignum25519 out, const unsigned char in[32]);

/* check if r is on curve */
int ge25519_check(const ge25519 *r);

/* a == b */
int ge25519_eq(const ge25519 *a, const ge25519 *b);

/* copies one point to another */
void ge25519_copy(ge25519 *dst, const ge25519 *src);

/* sets B point to r */
void ge25519_set_base(ge25519 *r);

/* 8*P */
void ge25519_mul8(ge25519 *r, const ge25519 *t);

/* -P */
void ge25519_neg_partial(ge25519 *r);

/* -P */
void ge25519_neg_full(ge25519 *r);

/* reduce all coords */
void ge25519_reduce(ge25519 *r, const ge25519 *t);

/* normalizes coords. (x, y, 1, x*y) */
void ge25519_norm(ge25519 *r, const ge25519 * t);

/* Simple addition */
void ge25519_add(ge25519 *r, const ge25519 *a, const ge25519 *b, unsigned char signbit);

/* point from bytes, used in H_p() */
void ge25519_fromfe_frombytes_vartime(ge25519 *r, const unsigned char *s);

/* point from bytes */
int ge25519_unpack_vartime(ge25519 *r, const unsigned char *s);

/* aG, wrapper for niels base mult. */
void ge25519_scalarmult_base_wrapper(ge25519 *r, const bignum256modm s);

/* aP, wrapper. General purpose, normalizes after multiplication */
void ge25519_scalarmult_wrapper(ge25519 *r, const ge25519 *P, const bignum256modm a);

#endif

+ 112
- 5
ed25519-donna/modm-donna-32bit.c View File

@@ -216,13 +216,13 @@ void mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y)
c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]);
f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30;
c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]);
f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30;
f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30;
c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]);
f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30;
f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30;
c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]);
f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30;
f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30;
c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]);
f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30;
f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30;
c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]);
f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30;
c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]);
@@ -282,7 +282,7 @@ void expand256_modm(bignum256modm out, const unsigned char *in, size_t len) {
q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff;
q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff;
q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff;
q1[8] = ((x[15] >> 8) );
q1[8] = ((x[15] >> 8) );

barrett_reduce256_modm(out, q1, out);
}
@@ -408,3 +408,110 @@ void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, i
}
}
}

void set256_modm(bignum256modm r, uint64_t v) {
r[0] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30;
r[1] = (bignum256modm_element_t) (v & 0x3fffffff); v >>= 30;
r[2] = (bignum256modm_element_t) (v & 0x3fffffff);
r[3] = 0;
r[4] = 0;
r[5] = 0;
r[6] = 0;
r[7] = 0;
r[8] = 0;
}

int get256_modm(uint64_t * v, const bignum256modm r){
*v = 0;
int con1 = 0;

#define NONZ(x) ((((((int64_t)(x)) - 1) >> 32) + 1) & 1)
bignum256modm_element_t c = 0;
c = r[0]; *v += (uint64_t)c & 0x3fffffff; c >>= 30; // 30
c += r[1]; *v += ((uint64_t)c & 0x3fffffff) << 30; c >>= 30; // 60
c += r[2]; *v += ((uint64_t)c & 0xf) << 60; con1 |= NONZ(c>>4); c >>= 30; // 64 bits
c += r[3]; con1 |= NONZ(c); c >>= 30;
c += r[4]; con1 |= NONZ(c); c >>= 30;
c += r[5]; con1 |= NONZ(c); c >>= 30;
c += r[6]; con1 |= NONZ(c); c >>= 30;
c += r[7]; con1 |= NONZ(c); c >>= 30;
c += r[8]; con1 |= NONZ(c); c >>= 30;
con1 |= NONZ(c);
#undef NONZ

return con1 ^ 1;
}

int eq256_modm(const bignum256modm x, const bignum256modm y){
size_t differentbits = 0;
int len = bignum256modm_limb_size;
while (len--) {
differentbits |= (*x++ ^ *y++);
}
return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb));
}

int cmp256_modm(const bignum256modm x, const bignum256modm y){
int len = 2*bignum256modm_limb_size;
uint32_t a_gt = 0;
uint32_t b_gt = 0;

// 16B chunks
while (len--) {
const uint32_t ln = (const uint32_t) len;
const uint32_t a = (x[ln>>1] >> 16*(ln & 1)) & 0xffff;
const uint32_t b = (y[ln>>1] >> 16*(ln & 1)) & 0xffff;

const uint32_t limb_a_gt = ((b - a) >> 16) & 1;
const uint32_t limb_b_gt = ((a - b) >> 16) & 1;
a_gt |= limb_a_gt & ~b_gt;
b_gt |= limb_b_gt & ~a_gt;
}

return a_gt - b_gt;
}

int iszero256_modm(const bignum256modm x){
size_t differentbits = 0;
int len = bignum256modm_limb_size;
while (len--) {
differentbits |= (*x++);
}
return (int) (1 & ((differentbits - 1) >> bignum256modm_bits_per_limb));
}

void copy256_modm(bignum256modm r, const bignum256modm x){
r[0] = x[0];
r[1] = x[1];
r[2] = x[2];
r[3] = x[3];
r[4] = x[4];
r[5] = x[5];
r[6] = x[6];
r[7] = x[7];
r[8] = x[8];
}

int check256_modm(const bignum256modm x){
int ok = 1;
bignum256modm t={0}, z={0};

ok &= iszero256_modm(x) ^ 1;
barrett_reduce256_modm(t, z, x);
ok &= eq256_modm(t, x);
return ok;
}

void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){
//(cc - aa * bb) % l
bignum256modm t={0};
mul256_modm(t, a, b);
sub256_modm(r, c, t);
}

void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c){
//(cc + aa * bb) % l
bignum256modm t={0};
mul256_modm(t, a, b);
add256_modm(r, c, t);
}

+ 27
- 0
ed25519-donna/modm-donna-32bit.h View File

@@ -51,3 +51,30 @@ void contract256_modm(unsigned char out[32], const bignum256modm in);
void contract256_window4_modm(signed char r[64], const bignum256modm in);

void contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize);

/* 64bit uint to scalar value */
void set256_modm(bignum256modm r, uint64_t v);

/* scalar value to 64bit uint */
int get256_modm(uint64_t * v, const bignum256modm r);

/* equality test on two reduced scalar values */
int eq256_modm(const bignum256modm x, const bignum256modm y);

/* comparison of two reduced scalar values */
int cmp256_modm(const bignum256modm x, const bignum256modm y);

/* scalar null check, has to be reduced */
int iszero256_modm(const bignum256modm x);

/* simple copy, no reduction */
void copy256_modm(bignum256modm r, const bignum256modm x);

/* check if nonzero && same after reduction */
int check256_modm(const bignum256modm x);

/* (cc - aa * bb) % l */
void mulsub256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c);

/* (cc + aa * bb) % l */
void muladd256_modm(bignum256modm r, const bignum256modm a, const bignum256modm b, const bignum256modm c);

+ 243
- 0
monero/base58.c View File

@@ -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;
}

+ 43
- 0
monero/base58.h View File

@@ -0,0 +1,43 @@
// 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

#ifndef __XMR_BASE58_H__
#define __XMR_BASE58_H__

#include <stdbool.h>
#include "hasher.h"
#include "options.h"

int xmr_base58_addr_encode_check(uint64_t tag, const uint8_t *data, size_t binsz, char *b58, size_t b58sz);
int xmr_base58_addr_decode_check(const char *addr, size_t sz, uint64_t *tag, void *data, size_t datalen);
bool xmr_base58_encode(char *b58, size_t *b58sz, const void *data, size_t binsz);
bool xmr_base58_decode(const char *b58, size_t b58sz, void *data, size_t *binsz);

#endif

+ 77
- 0
monero/int-util.h View File

@@ -0,0 +1,77 @@
// 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

#pragma once

#include <assert.h>
#include <stdint.h>

static inline uint64_t hi_dword(uint64_t val) {
return val >> 32;
}

static inline uint64_t lo_dword(uint64_t val) {
return val & 0xFFFFFFFF;
}

static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) {
// multiplier = ab = a * 2^32 + b
// multiplicand = cd = c * 2^32 + d
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
uint64_t a = hi_dword(multiplier);
uint64_t b = lo_dword(multiplier);
uint64_t c = hi_dword(multiplicand);
uint64_t d = lo_dword(multiplicand);

uint64_t ac = a * c;
uint64_t ad = a * d;
uint64_t bc = b * c;
uint64_t bd = b * d;

uint64_t adbc = ad + bc;
uint64_t adbc_carry = adbc < ad ? 1 : 0;

// multiplier * multiplicand = product_hi * 2^64 + product_lo
uint64_t product_lo = bd + (adbc << 32);
uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
*product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
assert(ac <= *product_hi);

return product_lo;
}

#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \
(((uint64_t) (x) & 0x000000000000ff00) << 40) | \
(((uint64_t) (x) & 0x0000000000ff0000) << 24) | \
(((uint64_t) (x) & 0x00000000ff000000) << 8) | \
(((uint64_t) (x) & 0x000000ff00000000) >> 8) | \
(((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
(((uint64_t) (x) & 0xff00000000000000) >> 56))

+ 21
- 0
monero/monero.h View File

@@ -0,0 +1,21 @@
//
// Created by Dusan Klinec on 10/05/2018.
//

#ifndef TREZOR_CRYPTO_MONERO_H
#define TREZOR_CRYPTO_MONERO_H

#if !USE_MONERO
#error "Compile with -DUSE_MONERO=1"
#endif

#if !USE_KECCAK
#error "Compile with -DUSE_KECCAK=1"
#endif

#include "base58.h"
#include "serialize.h"
#include "xmr.h"
#include "range_proof.h"

#endif //TREZOR_CRYPTO_MONERO_H

+ 115
- 0
monero/range_proof.c View File

@@ -0,0 +1,115 @@
//
// Created by Dusan Klinec on 10/05/2018.
//

#include "range_proof.h"


static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p){
unsigned char buff[32];
ge25519_pack(buff, p);
xmr_hash_to_scalar(r, buff, sizeof(buff));
}

void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask){
bignum256modm ai[64];
bignum256modm alpha[64];
xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha);
}

void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask,
bignum256modm ai[64], bignum256modm alpha[64])
{
const unsigned n = XMR_ATOMS;
bignum256modm a={0};
bignum256modm si={0};
bignum256modm c={0};
bignum256modm ee={0};
unsigned char buff[32];

Hasher kck;
xmr_hasher_init(&kck);

ge25519 C_acc;
ge25519 C_h;
ge25519 C_tmp;
ge25519 L;
ge25519 Zero;

ge25519_set_neutral(&Zero);
ge25519_set_neutral(&C_acc);
ge25519_set_xmr_h(&C_h);
set256_modm(a, 0);

#define BB(i) ((amount>>(i)) & 1)

// First pass, generates: ai, alpha, Ci, ee, s1
for(unsigned ii=0; ii<n; ++ii){
xmr_random_scalar(ai[ii]);
if (last_mask != NULL && ii == n - 1){
sub256_modm(ai[ii], *last_mask, a);
}

add256_modm(a, a, ai[ii]); // creating the total mask since you have to pass this to receiver...
xmr_random_scalar(alpha[ii]);

ge25519_scalarmult_base_niels(&L, ge25519_niels_base_multiples, alpha[ii]);
ge25519_scalarmult_base_niels(&C_tmp, ge25519_niels_base_multiples, ai[ii]);

// C_tmp += &Zero if BB(ii) == 0 else &C_h
ge25519_add(&C_tmp, &C_tmp, BB(ii) == 0 ? &Zero : &C_h, 0);
ge25519_add(&C_acc, &C_acc, &C_tmp, 0);

// Set Ci[ii] to sigs
ge25519_pack(sig->Ci[ii], &C_tmp);

if (BB(ii) == 0) {
xmr_random_scalar(si);
xmr_hash_ge25519_to_scalar(c, &L);

ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h
xmr_add_keys2_vartime(&L, si, c, &C_tmp);

// Set s1[ii] to sigs
contract256_modm(sig->asig.s1[ii], si);
}

ge25519_pack(buff, &L);
xmr_hasher_update(&kck, buff, sizeof(buff));

ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2)
}

// Compute ee
xmr_hasher_final(&kck, buff);
expand256_modm(ee, buff, sizeof(buff));

ge25519_set_xmr_h(&C_h);

// Second pass, s0, s1
for(unsigned ii=0; ii<n; ++ii){
if (BB(ii) == 0){
mulsub256_modm(si, ai[ii], ee, alpha[ii]);
contract256_modm(sig->asig.s0[ii], si);

} else {
xmr_random_scalar(si);
contract256_modm(sig->asig.s0[ii], si);

ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]);
xmr_add_keys2_vartime(&L, si, ee, &C_tmp);
xmr_hash_ge25519_to_scalar(c, &L);

mulsub256_modm(si, ai[ii], c, alpha[ii]);
contract256_modm(sig->asig.s1[ii], si);
}

ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2)
}

ge25519_copy(C, &C_acc);
copy256_modm(mask, a);
contract256_modm(sig->asig.ee, ee);
#undef BB
}


+ 30
- 0
monero/range_proof.h View File

@@ -0,0 +1,30 @@
//
// Created by Dusan Klinec on 10/05/2018.
//

#ifndef TREZOR_CRYPTO_RANGE_PROOF_H
#define TREZOR_CRYPTO_RANGE_PROOF_H

#include "xmr.h"
#define XMR_ATOMS 64

typedef uint64_t xmr_amount;
typedef xmr_key_t xmr_key64_t[64];

typedef struct xmr_boro_sig {
xmr_key64_t s0;
xmr_key64_t s1;
xmr_key_t ee;
} xmr_boro_sig_t;

typedef struct range_sig {
xmr_boro_sig_t asig;
xmr_key64_t Ci;
} xmr_range_sig_t;


void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask);
void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask,
bignum256modm ai[64], bignum256modm alpha[64]);

#endif //TREZOR_CRYPTO_RANGE_PROOF_H

+ 54
- 0
monero/serialize.c View File

@@ -0,0 +1,54 @@
//
// Created by Dusan Klinec on 02/05/2018.
//

#include "serialize.h"

int xmr_size_varint(uint64_t num){
int ctr = 1;
while (num >= 0x80) {
++ctr;
num >>= 7;
}
return ctr;
}

int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num){
unsigned ctr = 0;
while (num >= 0x80 && ctr < buff_size) {
*buff = (uint8_t) (((num) & 0x7f) | 0x80);
++buff;
++ctr;
num >>= 7;
}

/* writes the last one to dest */
if (ctr < buff_size) {
*buff = (uint8_t) num;
++ctr;
}
return ctr <= buff_size ? (int)ctr : -1;
}

int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val) {
unsigned read = 0;
int finished_ok = 0;
*val = 0;

for (int shift = 0; read < buff_size; shift += 7, ++read) {
uint8_t byte = buff[read];
if (byte == 0 && shift != 0) {
return -1;
}

*val |= (uint64_t)(byte & 0x7f) << shift;

/* If there is no next */
if ((byte & 0x80) == 0) {
finished_ok = 1;
break;
}
}
return finished_ok ? (int)read + 1 : -2;
}


+ 15
- 0
monero/serialize.h View File

@@ -0,0 +1,15 @@
//
// Created by Dusan Klinec on 02/05/2018.
//

#ifndef TREZOR_XMR_SERIALIZE_H
#define TREZOR_XMR_SERIALIZE_H

#include <stddef.h>
#include <stdint.h>

int xmr_size_varint(uint64_t num);
int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num);
int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val);

#endif //TREZOR_XMR_SERIALIZE_H

+ 159
- 0
monero/xmr.c View File

@@ -0,0 +1,159 @@
//
// Created by Dusan Klinec on 10/05/2018.
//

#include "xmr.h"
#include "int-util.h"
#include "serialize.h"
#include "rand.h"


const ge25519 ALIGN(16) xmr_h = {
{0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73},
{0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9},
{0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4},
{0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df}
};


void ge25519_set_xmr_h(ge25519 *r){
ge25519_copy(r, &xmr_h);
}

void xmr_random_scalar(bignum256modm m){
unsigned char buff[32]={0};
random_buffer(buff, sizeof(buff));
expand256_modm(m, buff, sizeof(buff));
}

void xmr_fast_hash(uint8_t * hash, const void *data, size_t length){
hasher_Raw(HASHER_SHA3K, data, length, hash);
}

void xmr_hasher_init(Hasher * hasher){
hasher_Init(hasher, HASHER_SHA3K);
}

void xmr_hasher_update(Hasher * hasher, const void *data, size_t length){
hasher_Update(hasher, data, length);
}

void xmr_hasher_final(Hasher * hasher, uint8_t * hash){
hasher_Final(hasher, hash);
}

void xmr_hasher_copy(Hasher * dst, const Hasher * src){
memcpy(dst, src, sizeof(Hasher));
}

void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length){
uint8_t hash[HASHER_DIGEST_LENGTH];
hasher_Raw(HASHER_SHA3K, data, length, hash);
expand256_modm(r, hash, HASHER_DIGEST_LENGTH);
}

void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length){
ge25519 point2;
uint8_t hash[HASHER_DIGEST_LENGTH];
hasher_Raw(HASHER_SHA3K, data, length, hash);

ge25519_fromfe_frombytes_vartime(&point2, hash);
ge25519_mul8(P, &point2);
}

void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index){
uint8_t buff[32 + 8];
ge25519_pack(buff, p);
int written = xmr_write_varint(buff + 32, 8, output_index);
xmr_hash_to_scalar(s, buff, 32u + written);
}

void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b){
ge25519 bA;
ge25519_scalarmult(&bA, A, b);
ge25519_norm(&bA, &bA);
ge25519_mul8(r, &bA);
}

void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base){
xmr_derivation_to_scalar(s, deriv, idx);
add256_modm(s, s, base);
}

void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base){
bignum256modm s={0};
ge25519 p2;
ge25519_pniels Bp;
ge25519_p1p1 p1;

xmr_derivation_to_scalar(s, deriv, idx);
ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s);
ge25519_norm(&p2, &p2);

ge25519_full_to_pniels(&Bp, base);
ge25519_pnielsadd_p1p1(&p1, &p2, &Bp, 0);
ge25519_p1p1_to_full(r, &p1);
}

void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){
// aG + bB, G is basepoint
ge25519 aG, bB;
ge25519_pniels bBn;
ge25519_p1p1 p1;
ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a);
ge25519_scalarmult(&bB, B, b);
ge25519_norm(&bB, &bB);
ge25519_norm(&aG, &aG);

ge25519_full_to_pniels(&bBn, &bB);
ge25519_pnielsadd_p1p1(&p1, &aG, &bBn, 0);
ge25519_p1p1_to_full(r, &p1);
}

void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){
// aG + bB, G is basepoint
ge25519_double_scalarmult_vartime(r, B, b, a);
ge25519_norm(r, r);
}

void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){
// aA + bB
ge25519 aA, bB;
ge25519_pniels bBn;
ge25519_p1p1 p1;
ge25519_scalarmult(&aA, A, a);
ge25519_scalarmult(&bB, B, b);
ge25519_norm(&bB, &bB);
ge25519_norm(&aA, &aA);

ge25519_full_to_pniels(&bBn, &bB);
ge25519_pnielsadd_p1p1(&p1, &aA, &bBn, 0);
ge25519_p1p1_to_full(r, &p1);
}

void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){
// aA + bB
ge25519_double_scalarmult_vartime2(r, A, a, B, b);
ge25519_norm(r, r);
}

void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m){
const char prefix[] = "SubAddr";
unsigned char buff[32];
contract256_modm(buff, m);

char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)];
memcpy(data, prefix, sizeof(prefix));
memcpy(data + sizeof(prefix), buff, sizeof(buff));
memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t));
memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, sizeof(uint32_t));

xmr_hash_to_scalar(r, data, sizeof(data));
}

void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount){
// C = aG + bH
bignum256modm b={0};
set256_modm(b, amount);
xmr_add_keys2(r, a, b, &xmr_h);
}

+ 67
- 0
monero/xmr.h View File

@@ -0,0 +1,67 @@
//
// Created by Dusan Klinec on 10/05/2018.
//

#ifndef TREZOR_CRYPTO_XMR_H
#define TREZOR_CRYPTO_XMR_H

#include <ed25519-donna/ge25519.h>
#include "hasher.h"

extern const ge25519 ALIGN(16) xmr_h;

typedef unsigned char xmr_key_t[32];

typedef struct xmr_ctkey {
xmr_key_t dest;
xmr_key_t mask;
} xmr_ctkey_t;

/* sets H point to r */
void ge25519_set_xmr_h(ge25519 *r);

/* random scalar value */
void xmr_random_scalar(bignum256modm m);

/* cn_fast_hash */
void xmr_fast_hash(uint8_t * hash, const void *data, size_t length);

/* incremental hashing wrappers */
void xmr_hasher_init(Hasher * hasher);
void xmr_hasher_update(Hasher * hasher, const void *data, size_t length);
void xmr_hasher_final(Hasher * hasher, uint8_t * hash);
void xmr_hasher_copy(Hasher * dst, const Hasher * src);

/* H_s(buffer) */
void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length);

/* H_p(buffer) */
void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length);

/* derivation to scalar value */
void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index);

/* derivation */
void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b);

/* H_s(derivation || varint(output_index)) + base */
void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base);

/* H_s(derivation || varint(output_index))G + base */
void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base);

/* aG + bB, G is basepoint */
void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B);
void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B);

/* aA + bB */
void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B);
void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B);

/* subaddress secret */
void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m);

/* Generates Pedersen commitment C = aG + bH */
void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount);

#endif //TREZOR_CRYPTO_XMR_H

+ 49
- 0
tests/test_check.c View File

@@ -58,11 +58,13 @@
#include "ed25519-donna/ed25519.h"
#include "ed25519-donna/ed25519-donna.h"
#include "ed25519-donna/ed25519-keccak.h"
#include "ed25519-donna/ge25519.h"
#include "script.h"
#include "rfc6979.h"
#include "address.h"
#include "rc4.h"
#include "nem.h"
#include "monero/monero.h"

#if VALGRIND
/*
@@ -4808,6 +4810,10 @@ END_TEST
#include "test_check_cardano.h"
#endif

#if USE_MONERO
#include "test_check_monero.h"
#endif

// define test suite and cases
Suite *test_suite(void)
{
@@ -5008,9 +5014,11 @@ Suite *test_suite(void)
tcase_add_test(tc, test_ed25519_modl_sub);
suite_add_tcase(s, tc);

#if USE_MONERO
tc = tcase_create("ed25519_ge");
tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2);
suite_add_tcase(s, tc);
#endif

tc = tcase_create("script");
tcase_add_test(tc, test_output_script);
@@ -5067,6 +5075,47 @@ Suite *test_suite(void)
suite_add_tcase(s,tc);
#endif

#if USE_MONERO
tc = tcase_create("xmr_base58");
tcase_add_test(tc, test_xmr_base58);
suite_add_tcase(s, tc);

tc = tcase_create("xmr_crypto");
tcase_add_test(tc, test_xmr_getset256_modm);
tcase_add_test(tc, test_xmr_cmp256_modm);
tcase_add_test(tc, test_xmr_copy_check_modm);
tcase_add_test(tc, test_xmr_mulsub256_modm);
tcase_add_test(tc, test_xmr_muladd256_modm);
tcase_add_test(tc, test_xmr_curve25519_set);
tcase_add_test(tc, test_xmr_curve25519_consts);
tcase_add_test(tc, test_xmr_curve25519_tests);
tcase_add_test(tc, test_xmr_curve25519_expand_reduce);
tcase_add_test(tc, test_xmr_ge25519_base);
tcase_add_test(tc, test_xmr_ge25519_check);
tcase_add_test(tc, test_xmr_ge25519_scalarmult_base_wrapper);
tcase_add_test(tc, test_xmr_ge25519_scalarmult_wrapper);
tcase_add_test(tc, test_xmr_ge25519_ops);
suite_add_tcase(s, tc);

tc = tcase_create("xmr_xmr");
tcase_add_test(tc, test_xmr_check_point);
tcase_add_test(tc, test_xmr_h);
tcase_add_test(tc, test_xmr_fast_hash);
tcase_add_test(tc, test_xmr_hasher);
tcase_add_test(tc, test_xmr_hash_to_scalar);
tcase_add_test(tc, test_xmr_hash_to_ec);
tcase_add_test(tc, test_xmr_derivation_to_scalar);
tcase_add_test(tc, test_xmr_generate_key_derivation);
tcase_add_test(tc, test_xmr_derive_private_key);
tcase_add_test(tc, test_xmr_derive_public_key);
tcase_add_test(tc, test_xmr_add_keys2);
tcase_add_test(tc, test_xmr_add_keys3);
tcase_add_test(tc, test_xmr_get_subaddress_secret_key);
tcase_add_test(tc, test_xmr_gen_c);
tcase_add_test(tc, test_xmr_varint);
tcase_add_test(tc, test_xmr_gen_range_sig);
suite_add_tcase(s, tc);
#endif
return s;
}


+ 1216
- 0
tests/test_check_monero.h
File diff suppressed because it is too large
View File


Loading…
Cancel
Save