commit 75a6883d181436a999b246251198369a6cdae66b Author: Harald Wolff Date: Thu Apr 8 22:36:08 2021 +0200 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..683b515 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.o +*.so +*.a +*.dylib +*.dll +*.exe +curvecli +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4cc7524 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ + +SOURCES=curve.c curves.c sha256.c lsag.c utils.c mpztools.c rand.c +OBJECTS=$(SOURCES:%.c=src/%.o) + +CFLAGS=-Iinclude -Lgmp -fPIC -ggdb + +all: + +clean: + rm -f *.so *.a src/*.o + +curvecli: libcurve.a + gcc -o curvecli -L. src/curvecli.c $(CFLAGS) -lgmp libcurve.a + +libcurve.so: $(OBJECTS) + gcc -o libcurve.so -shared $(OBJECTS) +libcurve.a: $(OBJECTS) + ar cm libcurve.a $(OBJECTS) diff --git a/include/curve.h b/include/curve.h new file mode 100644 index 0000000..d60295a --- /dev/null +++ b/include/curve.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#define assert_zero(__c__) { if ((__c__)!=0) { printf("assert_zero: " __FILE__ "\n"); return -1; }; } +//#define assert_zero(__c__) __c__ + +#define DUMP_MPZ(__prefix__, __mpz__) { char t[128]; mpz_get_str(t, 16, __mpz__); printf(__prefix__ ": %s\n", t); }; + +struct ec_point +{ + mpz_t x, y; +}; +typedef struct ec_point ec_point_t[1]; + +/*** + * Define a curve of type y*y = x*x*x + a*x + b + ***/ +struct curve +{ + mpz_t p; + mpz_t a, b; + mpz_t n; + + int32_t h; + ec_point_t G; + + int bitwidth; +}; +typedef struct curve curve_t[1]; +int named_curves_count; + +int32_t curve_create_from_name(char *curve_name, curve_t curve); +int32_t curve_create(curve_t curve, mpz_t p, mpz_t a, mpz_t b, mpz_t n, int32_t h, mpz_t xg, mpz_t yg); +int32_t curve_destroy(curve_t curve); + +int32_t curve_point_init(ec_point_t point); +int32_t curve_point_init_set(ec_point_t point, ec_point_t src); +int32_t curve_point_init_set_xy(ec_point_t point, mpz_t x, mpz_t y); + +int32_t curve_point_clear(ec_point_t point); + +int32_t curve_point_is_valid(ec_point_t point, curve_t curve); +int32_t curve_point_is_infinity(ec_point_t point); + +int32_t curve_point_add(ec_point_t dst, ec_point_t p1, ec_point_t p2, curve_t curve); +int32_t curve_point_mul(ec_point_t dst, ec_point_t p1, mpz_t i, curve_t curve); + +int32_t curve_map_to_curve( ec_point_t dst, mpz_t u, curve_t curve); +int32_t curve_hash_to_point( ec_point_t dst, char *message, int len, curve_t curve); + +int32_t curve_get_generator( ec_point_t dst, curve_t curve ); + +static inline void curve_point_set(ec_point_t dst, ec_point_t src) { + mpz_set( dst->x, src->x ); + mpz_set( dst->y, src->y ); +}; + +static inline int32_t curve_point_equals(ec_point_t p1, ec_point_t p2) { return (mpz_cmp(p1->x, p2->x) == 0) && (mpz_cmp(p1->y, p2->y) == 0); } + +void sha256(char *message, int len, char *hash); +void sha256_curve_points(ec_point_t* points, int points_length, curve_t curve, char *hash); + +static inline void __tools_ec_point_cleanup(ec_point_t *p) { curve_point_clear( *p ); } + +#define ec_point_t_cleanup(name) ec_point_t name __attribute__ (( __cleanup__(__tools_ec_point_cleanup))); curve_point_init( name ); \ No newline at end of file diff --git a/include/lsag.h b/include/lsag.h new file mode 100644 index 0000000..f1988c7 --- /dev/null +++ b/include/lsag.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + + +int32_t lsag_sign (char *message, int mlen, mpz_t signKey, ec_point_t* public_keys, int public_keys_len, curve_t curve, mpz_t out_C0, ec_point_t out_Y, mpz_t* out_s); +int32_t lsag_verify (char *message, int mlen, ec_point_t* public_keys, int public_keys_len, curve_t curve, mpz_t C0, ec_point_t Y, mpz_t* s); + +int32_t lsag_hash_one(char *pkHash, ec_point_t y, char *msgHash, ec_point_t a, ec_point_t b, curve_t curve, mpz_t out_H1); + + +char *print_hex(char *p, int len); \ No newline at end of file diff --git a/include/mpztools.h b/include/mpztools.h new file mode 100644 index 0000000..bbff80a --- /dev/null +++ b/include/mpztools.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +struct mpz_field +{ + int length; + mpz_t values[0]; +}; +typedef struct mpz_field mpz_field_t; + + + + +#define mpz_field_value(f, i) (f->values[i]) + +static inline void __tools_mpz_cleanup(mpz_t *mpz){ + // printf("__tools_mpz_clenaup(%x)\n", mpz); + mpz_clear(*mpz); +} + +void mpz_random_mod( mpz_t rop, mpz_t p); +char* mpz_to_string(mpz_t i, int base); + +#define mpz_cleanup(name) mpz_t name __attribute__ (( __cleanup__(__tools_mpz_cleanup))); mpz_init( name ); +#define mpz_t_cleanup_set(name, value) mpz_t name __attribute__ (( __cleanup__(__tools_mpz_cleanup))); mpz_init_set( name, value ); + +mpz_t* mpz_field_init(int length); +void mpz_field_clear(mpz_t *field); + +static inline void __tools_mpz_field_cleanup(mpz_t **f){ + mpz_field_clear(*f); +} + +#define mpz_field_cleanup(name, length) mpz_t* name __attribute__ (( __cleanup__(__tools_mpz_field_cleanup))) = mpz_field_init( length ); + diff --git a/include/rand.h b/include/rand.h new file mode 100644 index 0000000..1c7e3fa --- /dev/null +++ b/include/rand.h @@ -0,0 +1,10 @@ +#pragma once + +void rand_init_auto(); +void rand_init_seeded(long seed); + +void rand_get_bytes(char *dst, int length); + + +void sha256(char *message, int len, char *hash); + diff --git a/include/sha256.h b/include/sha256.h new file mode 100644 index 0000000..0965012 --- /dev/null +++ b/include/sha256.h @@ -0,0 +1,35 @@ +/********************************************************************* +* Filename: sha256.h +* Author: Brad Conte (brad AT bradconte.com) https://github.com/B-Con/crypto-algorithms.git +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Defines the API for the corresponding SHA1 implementation. +*********************************************************************/ + +#ifndef SHA256_H +#define SHA256_H + +/*************************** HEADER FILES ***************************/ +#include +#include + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest + +/**************************** DATA TYPES ****************************/ +typedef uint8_t BYTE; // 8-bit byte +typedef uint32_t WORD; // 32-bit word, change to "long" for 16-bit machines + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[8]; +} SHA256_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha256_init(SHA256_CTX *ctx); +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len); +void sha256_final(SHA256_CTX *ctx, BYTE hash[]); + +#endif // SHA256_H \ No newline at end of file diff --git a/src/curve.c b/src/curve.c new file mode 100644 index 0000000..b3f8026 --- /dev/null +++ b/src/curve.c @@ -0,0 +1,229 @@ +#include +#include +#include + +int __ec_point_size = sizeof(struct ec_point); + +int32_t curve_create(curve_t curve, mpz_t p, mpz_t a, mpz_t b, mpz_t n, int32_t h, mpz_t xg, mpz_t yg) +{ + mpz_init_set( curve->p, p); + mpz_init_set( curve->a, a); + mpz_init_set( curve->b, b); + mpz_init_set( curve->n, n); + curve->h = h; + + curve->bitwidth = (mpz_sizeinbase( p , 2 ) + 7) & 0xFFFFFFF8; + + curve_point_init_set_xy(curve->G, xg, yg); + + if (curve->G) + return 0; + + mpz_clear( curve->n ); + mpz_clear( curve->b ); + mpz_clear( curve->a ); + mpz_clear( curve->p ); + + return -1; +}; + +int32_t curve_destroy(curve_t curve) +{ + if (curve) + { + if (!curve_point_clear( curve->G )) + { + mpz_clear( curve->n ); + mpz_clear( curve->b ); + mpz_clear( curve->a ); + mpz_clear( curve->p ); + return 0; + } + } + return -1; +} + +int32_t curve_get_generator( ec_point_t dst, curve_t curve ) +{ + mpz_set( dst->x, curve->G->x ); + mpz_set( dst->y, curve->G->y ); +} + +int32_t curve_point_init(ec_point_t point) +{ + mpz_init(point->x); + mpz_init(point->y); + return 0; +} + +int32_t curve_point_init_set(ec_point_t point, ec_point_t src) +{ + mpz_init_set(point->x, src->x); + mpz_init_set(point->y, src->y); + return 0; +} + +int32_t curve_point_init_set_xy(ec_point_t point, mpz_t x, mpz_t y) +{ + mpz_init_set(point->x, x); + mpz_init_set(point->y, y); + return 0; +} + + +int32_t curve_point_clear(ec_point_t point) +{ + mpz_clear(point->x); + mpz_clear(point->y); + return 0; +} + +int32_t curve_point_is_valid(ec_point_t point, curve_t curve) +{ + mpz_t yy, yy2; + mpz_inits( yy, yy2, NULL ); + + mpz_powm_ui( yy, point->x, 3, curve->p ); + mpz_addmul( yy, curve->a, point->x ); + mpz_add( yy, yy, curve->b ); + mpz_mod( yy, yy, curve->p ); + + mpz_powm_ui( yy2, point->y, 2, curve->p ); + + int result = mpz_cmp( yy, yy2 ) == 0; + mpz_clears( yy, yy2, NULL ); + return result; +} + +int32_t curve_point_is_infinity(ec_point_t point) +{ + return (mpz_cmp_ui(point->x, 0) == 0) && (mpz_cmp_ui(point->y, 0) == 0); +} + +int32_t curve_point_add(ec_point_t dst, ec_point_t p1, ec_point_t p2, curve_t curve) +{ + int xeq, yeq; + + xeq = mpz_cmp(p1->x, p2->x) == 0; + yeq = mpz_cmp(p1->y, p2->y) == 0; + + if (xeq && !yeq) + { + mpz_set_ui( dst->x, 0); + mpz_set_ui( dst->y, 0); + return 0; + } else { + int result = -1; + mpz_t lambda; + mpz_t divlambda; + + ec_point_t _p1; + ec_point_t _p2; + + curve_point_init_set( _p1, p1 ); + curve_point_init_set( _p2, p2 ); + + mpz_inits( lambda, divlambda, NULL ); + + if (xeq) + { + mpz_powm_ui(lambda, _p1->x, 2, curve->p); + mpz_mul_ui(lambda, lambda, 3); + mpz_add(lambda, lambda, curve->a); + mpz_mul_ui(divlambda, _p1->y, 2); + } else { + mpz_sub( lambda, _p2->y, _p1->y); + mpz_sub( divlambda, _p2->x, _p1->x); + } + + mpz_mod( lambda, lambda, curve->p ); + mpz_mod( divlambda, divlambda, curve->p ); + + if (mpz_invert( divlambda, divlambda, curve->p )==0) + { + printf("%s: no inverse found\n", __func__); + } else { + mpz_mul( lambda, lambda, divlambda ); + mpz_mod( lambda, lambda, curve->p ); + + mpz_powm_ui( dst->x, lambda, 2, curve->p ); + mpz_sub( dst->x, dst->x, _p1->x ); + mpz_sub( dst->x, dst->x, _p2->x ); + mpz_mod( dst->x, dst->x, curve->p ); + + mpz_sub( dst->y, _p1->x, dst->x ); + mpz_mul( dst->y, dst->y, lambda ); + mpz_sub( dst->y, dst->y, _p1->y ); + mpz_mod( dst->y, dst->y, curve->p ); + + result = 0; + } + + mpz_clears( lambda, divlambda, NULL ); + + curve_point_clear(_p1); + curve_point_clear(_p2); + + return result; + } + return -1; +} + +int32_t curve_point_mul(ec_point_t dst, ec_point_t p1, mpz_t i, curve_t curve) +{ + if (curve_point_is_infinity(p1) || (mpz_cmp_ui(p1->y, 0)==0)) + { + mpz_set_ui( dst->x, 0); + mpz_set_ui( dst->y, 0); + return 0; + } + + int firstOne = mpz_scan1( i, 0 ); + int size = (mpz_size( i ) * sizeof(mp_limb_t)) << 3; + + ec_point_t p; + curve_point_init_set(p, p1); + + int n=0; + for (;nn ); + curve_point_mul( dst, curve->G, u2, curve ); + return 0; +} + +int32_t curve_hash_to_point( ec_point_t dst, char *message, int len, curve_t curve) +{ + char hash[32]; + SHA256_CTX sha256; + + sha256_init(&sha256); + sha256_update(&sha256, message, len ); + sha256_final(&sha256, hash); + + mpz_cleanup(k); + mpz_import(k, 32, -1, 1, -1, 0, hash); + mpz_mul_ui( k, k, 0xdeadbeef ); + mpz_mod( k, k, curve->n); + + return curve_map_to_curve( dst, k, curve ); +} + diff --git a/src/curvecli.c b/src/curvecli.c new file mode 100644 index 0000000..694e4f2 --- /dev/null +++ b/src/curvecli.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +char curvename[32]; + + +void test_lsag(int ringsize) +{ + curve_t secp256k1; + curve_create_from_name("secp256k1", secp256k1); + + mpz_t privKeys[ringsize]; + ec_point_t pubKeys[ringsize]; + + for (int i=0; in ); + curve_point_init( pubKeys[i] ); + curve_point_mul( pubKeys[i], secp256k1->G, privKeys[i], secp256k1 ); + } + + printf("LSAG: created ring of %i keys:\n", ringsize); + for (int i=0; i ", mpz_to_string(privKeys[i], 16)); + printf("%s / ", mpz_to_string(pubKeys[i]->x, 16)); + printf("%s\n", mpz_to_string(pubKeys[i]->y, 16)); + } + + char *message = "Hallo Welt!"; + int msglen = strlen(message); + + mpz_cleanup( C0 ); + ec_point_t_cleanup( Y ); + mpz_field_cleanup( S, ringsize ); + + + printf("LSAG: signing ring of %i keys:\n", ringsize); + for (int i=0; i + +#include +#include + +struct named_curve +{ + char *name; + char *p; + char *a,*b,*n; + int h; + char *gx,*gy; +}; + +struct named_curve named_curves[] = { + { + "secp256k1", + "00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "00", + "07", + "00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + 1, + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8" + }, +}; + +int named_curves_count = sizeof(named_curves) / sizeof(struct named_curve); + +int32_t curve_create_from_name(char *curve_name, curve_t curve) +{ + for (int i=0; i +#include +#include + +int32_t lsag_sign (char *message, int mlen, mpz_t signKey, ec_point_t* public_keys, int public_keys_len, curve_t curve, mpz_t out_C0, ec_point_t out_Y, mpz_t* out_s) +{ + ec_point_t signPubKey; + int signKeyIndex = -1; + curve_point_init( signPubKey ); + curve_point_mul( signPubKey, curve->G, signKey, curve ); + + for (int n=0; nn ); + + ec_point_t_cleanup(a); + ec_point_t_cleanup(b); + ec_point_t_cleanup(t); + + curve_point_mul( a, curve->G, u, curve ); + curve_point_mul( b, H, u, curve ); + lsag_hash_one(pkHash, out_Y, msgHash, a, b, curve, c[ (signKeyIndex+1) % public_keys_len ] ); + + for (int i=(signKeyIndex+1) % public_keys_len ; i != signKeyIndex ; i = (i+1)%public_keys_len ) + { + mpz_random_mod( out_s[i], curve->n ); + curve_point_mul( a, curve->G, out_s[i], curve ); + curve_point_mul( t, public_keys[i], c[i], curve ); + curve_point_add( a, a, t, curve ); + + curve_point_mul( b, H, out_s[i], curve ); + curve_point_mul( t, out_Y, c[i], curve ); + curve_point_add( b, b, t, curve ); + + lsag_hash_one(pkHash, out_Y, msgHash, a, b, curve, c[ (i+1) % public_keys_len ] ); + + // printf("sign: c[%i] = %s\n", i, mpz_to_string(c[i], 16)); + // printf("sign: s[%i] = %s\n", i, mpz_to_string(out_s[i], 16)); + } + + mpz_set( out_s[signKeyIndex], u ); + mpz_submul( out_s[signKeyIndex], signKey, c[signKeyIndex] ); + mpz_mod( out_s[signKeyIndex], out_s[signKeyIndex], curve->n ); + + // printf("sign: c[%i] = %s\n", signKeyIndex, mpz_to_string(c[signKeyIndex], 16)); + // printf("sign: s[%i] = %s\n", signKeyIndex, mpz_to_string(out_s[signKeyIndex], 16)); + + mpz_set( out_C0, c[0] ); + + return 0; +} + +int32_t lsag_verify (char *message, int mlen, ec_point_t* public_keys, int public_keys_len, curve_t curve, mpz_t C0, ec_point_t Y, mpz_t* s) +{ + // printf(" --- lsag_verify(): start --- \n"); + + char msgHash[32]; + char pkHash[32]; + + sha256( message, mlen, msgHash ); + sha256_curve_points( public_keys, public_keys_len, curve, pkHash ); + + // printf("msgHash: %s\n", print_hex(msgHash, 32)); + // printf("pkHash: %s\n", print_hex(pkHash, 32)); + + mpz_field_cleanup( c, public_keys_len + 1 ); + mpz_set( c[0], C0 ); + + // printf(" --- lsag_verify(): mark I --- \n"); + + ec_point_t_cleanup(H); + + // printf(" --- lsag_verify(): mark Ib --- \n"); + + curve_hash_to_point( H, pkHash, 32, curve ); + + ec_point_t_cleanup(a); + ec_point_t_cleanup(b); + ec_point_t_cleanup(t); + + // printf(" --- lsag_verify(): mark II --- \n"); + + for (int i=0 ; i < public_keys_len ; i++ ) + { + // printf("sign: c[%i] = %s\n", i, mpz_to_string(c[i], 16)); + // printf("sign: s[%i] = %s\n", i, mpz_to_string(s[i], 16)); + + curve_point_mul( a, curve->G, s[i], curve ); + curve_point_mul( t, public_keys[i], c[i], curve ); + curve_point_add( a, a, t, curve ); + + curve_point_mul( b, H, s[i], curve ); + curve_point_mul( t, Y, c[i], curve ); + curve_point_add( b, b, t, curve ); + + lsag_hash_one(pkHash, Y, msgHash, a, b, curve, c[ i+1 ] ); + } + return mpz_cmp(c[0], c[public_keys_len]) == 0; +} + +int32_t lsag_hash_one(char *pkHash, ec_point_t y, char *msgHash, ec_point_t a, ec_point_t b, curve_t curve, mpz_t out_H1) +{ + char h1[32]; + int keysize = curve->bitwidth >> 3; + char tv[keysize]; + SHA256_CTX sha; + + sha256_init( &sha ); + + sha256_update( &sha, pkHash, 32 ); + sha256_update( &sha, msgHash, 32 ); + + memset( tv, 0x00, keysize ); + mpz_export( tv, NULL, -1, 1, -1, 0, y->x ); + sha256_update( &sha, tv, keysize); + memset( tv, 0x00, keysize ); + mpz_export( tv, NULL, -1, 1, -1, 0, y->y ); + sha256_update( &sha, tv, keysize); + + memset( tv, 0x00, keysize ); + mpz_export( tv, NULL, -1, 1, -1, 0, a->x ); + sha256_update( &sha, tv, keysize); + memset( tv, 0x00, keysize ); + mpz_export( tv, NULL, -1, 1, -1, 0, a->y ); + sha256_update( &sha, tv, keysize); + + memset( tv, 0x00, keysize ); + mpz_export( tv, NULL, -1, 1, -1, 0, b->x ); + sha256_update( &sha, tv, keysize); + memset( tv, 0x00, keysize ); + mpz_export( tv, NULL, -1, 1, -1, 0, b->y ); + sha256_update( &sha, tv, keysize); + + sha256_final( &sha, h1 ); + + mpz_import( out_H1, 32, -1, 1, -1, 0, h1 ); + mpz_mul_ui( out_H1, out_H1, 0xdeadbeef ); + mpz_mod( out_H1, out_H1, curve->p ); + + return 0; +} + diff --git a/src/mpztools.c b/src/mpztools.c new file mode 100644 index 0000000..0998396 --- /dev/null +++ b/src/mpztools.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +mpz_t* mpz_field_init(int length) +{ + int *l = malloc( sizeof(int) + (sizeof(mpz_t) * length)); + *l = length; + mpz_t *f = (mpz_t*) (++l); + for (int n=0;n> 3; + char b[ bytesize * 2 ]; + rand_get_bytes( b, bytesize * 2 ); + mpz_import( rop, bytesize * 2, -1, 1, -1, 0, b ); + mpz_mod( rop, rop, p ); +} + +char* mpz_to_string(mpz_t i, int base) +{ + static char *s = NULL; + static int slen = 0; + int neededsize = mpz_sizeinbase(i, base) + 2; + + if (slen < neededsize) + { + if (s) + free(s); + s = malloc(neededsize); + slen = neededsize; + } + mpz_get_str(s, base, i ); + return s; +} \ No newline at end of file diff --git a/src/rand.c b/src/rand.c new file mode 100644 index 0000000..cb38b6e --- /dev/null +++ b/src/rand.c @@ -0,0 +1,52 @@ +#include + +#include +#include +#include +#include + +#include + +char __rand_state[32]; +int __rand_seeded = 0; + +void rand_init_auto() +{ + int f = open("/dev/random", O_RDONLY); + read( f, __rand_state, 32 ); + close(f); + + __rand_seeded = 1; +} + +void rand_init_seeded(long seed) +{ + memset( __rand_state, 0x00, 32 ); + memcpy(__rand_state, &seed, 8 ); + + sha256(__rand_state, 32, __rand_state); + sha256(__rand_state, 32, __rand_state); + sha256(__rand_state, 32, __rand_state); + sha256(__rand_state, 32, __rand_state); + + __rand_seeded = 1; +} + +void rand_get_bytes(char *dst, int length) +{ + if (!__rand_seeded) + rand_init_auto(); + + while (length > 0) + { + int l = length > 32 ? 32 : length; + + sha256(__rand_state, 32, __rand_state); + memcpy( dst, __rand_state, l); + + length -= l; + dst += l; + } + + sha256(__rand_state, 32, __rand_state); +} diff --git a/src/sha256.c b/src/sha256.c new file mode 100644 index 0000000..e27de3a --- /dev/null +++ b/src/sha256.c @@ -0,0 +1,158 @@ +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) https://github.com/B-Con/crypto-algorithms.git +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include +#include +#include "sha256.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void sha256_init(SHA256_CTX *ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len) +{ + WORD i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void sha256_final(SHA256_CTX *ctx, BYTE hash[]) +{ + WORD i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } + else { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[63] = ctx->bitlen; + ctx->data[62] = ctx->bitlen >> 8; + ctx->data[61] = ctx->bitlen >> 16; + ctx->data[60] = ctx->bitlen >> 24; + ctx->data[59] = ctx->bitlen >> 32; + ctx->data[58] = ctx->bitlen >> 40; + ctx->data[57] = ctx->bitlen >> 48; + ctx->data[56] = ctx->bitlen >> 56; + sha256_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; + } +} \ No newline at end of file diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..f29c4a4 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,60 @@ +#include +#include + +char hexdigits[] = "0123456789ABCDEF"; + + +void sha256(char *message, int len, char *hash) +{ + SHA256_CTX sha; + sha256_init( &sha ); + sha256_update( &sha, message, len ); + sha256_final( &sha, hash ); +} + +void sha256_curve_points(ec_point_t* points, int points_length, curve_t curve, char *hash) +{ + SHA256_CTX sha; + int blen = curve->bitwidth >> 3; + char b[blen]; + + sha256_init( &sha ); + + for (int i=0;ix ); + sha256_update( &sha, b, blen ); + + memset( b, 0x00, blen ); + mpz_export( b, NULL, -1, 1, -1, 0, points[i]->y ); + sha256_update( &sha, b, blen ); + } + + sha256_final( &sha, hash); +} + +char *print_hex(char *p, int len) +{ + static char *s = NULL; + static int slen = 0; + int minsize = (len<<1)+1; + + if (slen < minsize) + { + if (s) + free(s); + s = malloc(minsize); + slen = minsize; + } + + for (int i=0; i>4) & 0x0f ]; + s[ (i<<1) +1 ]= hexdigits[ (p[i]) & 0x0f ]; + } + s[minsize-1] = 0x00; + + return s; + +} \ No newline at end of file