libswarm-ng

C implementation of BMT hasher, Swarmhash and Single Owner Chunk for swarm
git clone git://git.defalsify.org/libswarm-ng.git
Log | Files | Refs | Submodules | README

commit 98fd2307066fa973bf2aad98ff60f7e8dce6714a
parent 8540fff2831fcabede856bf7f8b45c2cbcd807fe
Author: nolash <dev@holbrook.no>
Date:   Thu, 16 Sep 2021 23:11:22 +0200

Add generate address and publickey on key struct

Diffstat:
MMakefile.dev | 8+++++---
Msrc/chunk.c | 21++++++++++++++++++++-
Msrc/chunk.h | 1+
Msrc/def.h | 1+
Msrc/keystore.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/keystore.h | 6++++++
Msrc/soc.c | 42++++++++++++++++++++++++++++++++++++++++++
Msrc/soc.h | 4+++-
Atest/check_chunk.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/check_keystore.c | 29++++++++++++++++++++++++++---
Mtest/check_soc.c | 40++++++++++++++++++++++++++++++++++++++++
Mtest/common.c | 29-----------------------------
Mtest/common.h | 1-
13 files changed, 290 insertions(+), 38 deletions(-)

diff --git a/Makefile.dev b/Makefile.dev @@ -50,6 +50,7 @@ build_check_common: build_check: build_base build_check_common $(CC) -I./src -o build/test/check_bmt build/swarm.o build/bmt.o build/endian.o build/swarmfile.o test/check_bmt.c $(CFLAGS_CHECK) -lcheck -lkeccak-tiny -ltestcommon -lsecp256k1 $(CC) -I./src -o build/test/check_file build/swarm.o build/bmt.o build/endian.o build/swarmfile.o test/check_file.c $(CFLAGS_CHECK) -lcheck -lkeccak-tiny -ltestcommon -lsecp256k1 + $(CC) -I./src -o build/test/check_chunk build/chunk.o build/swarm.o build/bmt.o build/endian.o build/swarmfile.o test/check_chunk.c $(CFLAGS_CHECK) -lcheck -lkeccak-tiny -ltestcommon -lsecp256k1 build_check_keystore: build_base build_keystore build_check_common @@ -57,7 +58,7 @@ build_check_keystore: build_base build_keystore build_check_common build_check_soc: build build_check_common build_soc - $(CC) -I./src -o build/test/check_soc build/chunk.o build/swarm.o build/soc.o test/check_soc.c -L./aux/secp256k1/.libs $(CFLAGS_CHECK) -lcheck -lkeccak-tiny -ltestcommon -lsecp256k1 + $(CC) -I./src -o build/test/check_soc build/keystore.o build/endian.o build/bmt.o build/chunk.o build/swarm.o build/soc.o test/check_soc.c -L./aux/secp256k1/.libs $(CFLAGS_CHECK) -lcheck -lkeccak-tiny -ltestcommon -lsecp256k1 build_lib: build $(CC) -fPIC -rdynamic --shared -o build/lib/libswarm.so build/swarm.o build/swarmfile.o build/bmt.o build/endian.o @@ -66,8 +67,9 @@ build_lib: build .PHONY: test clean check_base: build build_check - LD_LIBRARY_PATH=./build/:./build/test CK_FORK=no build/test/check_bmt - LD_LIBRARY_PATH=./build/:./build/test CK_FORK=no build/test/check_file + #LD_LIBRARY_PATH=./build/:./build/test CK_FORK=no build/test/check_bmt + LD_LIBRARY_PATH=./build/:./build/test CK_FORK=no build/test/check_chunk + #LD_LIBRARY_PATH=./build/:./build/test CK_FORK=no build/test/check_file check_keystore: build build_check_keystore LD_LIBRARY_PATH=./build/:./build/test CK_FORK=no build/test/check_keystore diff --git a/src/chunk.c b/src/chunk.c @@ -1,7 +1,8 @@ -#include <string.h> #include <stddef.h> +#include "string.h" #include "chunk.h" +#include "bmt.h" unsigned char* chunk_serialize(const swarm_chunk_t *chunk, unsigned char *z, size_t *sz) { int crsr; @@ -16,3 +17,21 @@ unsigned char* chunk_serialize(const swarm_chunk_t *chunk, unsigned char *z, siz return z; } + +int chunk_verify(const swarm_chunk_t *chunk) { + int r; + bmt_t bctx; + + bmt_init(&bctx, chunk->payload, chunk->payload_sz, (bmt_spansize_t)*chunk->span); + r = bmt_sum(&bctx); + if (r != 0) { + return 1; + } + + r = memcmp(chunk->hash, bctx.buf, SWARM_WORD_SIZE); + if (r != 0) { + return 1; + } + + return 0; +} diff --git a/src/chunk.h b/src/chunk.h @@ -12,5 +12,6 @@ typedef struct swarm_chunk { } swarm_chunk_t; unsigned char* chunk_serialize(const swarm_chunk_t *chunk, unsigned char *z, size_t *sz); +int chunk_verify(const swarm_chunk_t *chunk); #endif // _LIBSWARM_CHUNK_H diff --git a/src/def.h b/src/def.h @@ -6,6 +6,7 @@ #define SWARM_PRIVATE_KEY_SIZE 32 #define SWARM_KEY_LABEL_SIZE 20 #define SWARM_PUBLIC_KEY_SIZE 65 +#define SWARM_PUBLIC_KEY_COMPRESSED_SIZE 33 #define SWARM_SIGNATURE_SIZE 65 #define SWARM_KECCAK_RATE 200-64 diff --git a/src/keystore.c b/src/keystore.c @@ -50,3 +50,93 @@ keystore_key_t* keystore_get(const keystore_t *keystore, keystore_key_t *z, cons memcpy(z, keystore->keys+idx, sizeof(keystore_key_t)); return z; } + + +int key_from_public(keystore_key_t *key) { + int r; + secp256k1_context *ecctx; + unsigned char digest[SWARM_WORD_SIZE]; + + r = keccak_hash_btc(digest, SWARM_WORD_SIZE, key->pubk + 1, SWARM_PUBLIC_KEY_SIZE - 1); + if (r < 0) { + return 1; + } + + memcpy(key->label, digest + SWARM_WORD_SIZE - SWARM_ADDRESS_SIZE, SWARM_ADDRESS_SIZE); + + return 0; +} + + +int key_from_private(keystore_key_t *key) { + int r; + secp256k1_context *ecctx; + secp256k1_pubkey public_key_o; + size_t public_key_sz; + unsigned char *p; + + ecctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + r = secp256k1_ec_pubkey_create(ecctx, &public_key_o, key->pk); + if (r == 0) { + return 1; + } + + public_key_sz = SWARM_PUBLIC_KEY_SIZE; + r = secp256k1_ec_pubkey_serialize(ecctx, key->pubk, &public_key_sz, &public_key_o, SECP256K1_EC_UNCOMPRESSED); + if (r == 0) { + return 1; + } + + r = key_from_public(key); + if (r != 0) { + return 1; + } + + return 0; +} + + +int key_recover_compact(const unsigned char *signature, unsigned char *public_key, const unsigned char *digest) { + int r; + size_t public_key_sz; + + secp256k1_context *ecctx; + secp256k1_ecdsa_recoverable_signature signature_o; + secp256k1_pubkey public_key_o; + + ecctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + + r = secp256k1_ecdsa_recoverable_signature_parse_compact(ecctx, &signature_o, signature, (int)*(signature+64)); + if (r == 0) { + return 1; + } + + r = secp256k1_ecdsa_recover(ecctx, &public_key_o, &signature_o, digest); + if (r == 0) { + return 1; + } + + public_key_sz = SWARM_PUBLIC_KEY_SIZE; + r = secp256k1_ec_pubkey_serialize(ecctx, public_key, &public_key_sz, &public_key_o, SECP256K1_EC_UNCOMPRESSED); + if (r == 0) { + return 1; + } + if (public_key_sz != SWARM_PUBLIC_KEY_SIZE) { + return 1; + } + + return 0; +} + + +keystore_key_t* key_recover(keystore_key_t *z, const unsigned char *signature, const unsigned char *digest) { + int r; + + r = key_recover_compact(signature, z->pubk, digest); + if (r != 0) { + return NULL; + } + + return z; +} diff --git a/src/keystore.h b/src/keystore.h @@ -5,9 +5,11 @@ typedef struct keystore_key { unsigned char pk[SWARM_PRIVATE_KEY_SIZE]; + unsigned char pubk[SWARM_PUBLIC_KEY_SIZE]; unsigned char label[SWARM_KEY_LABEL_SIZE]; } keystore_key_t; + typedef struct keystore { size_t pk_sz; size_t label_sz; @@ -17,8 +19,12 @@ typedef struct keystore { keystore_key_t* (*label)(keystore_key_t *key); } keystore_t; + keystore_key_t* keystore_put(keystore_t *keystore, const keystore_key_t *z, const char *passphrase, size_t passphrase_sz); keystore_key_t* keystore_get(const keystore_t *keystore, keystore_key_t *z, const int idx); unsigned char* keystore_sign(const keystore_t *keystore, unsigned char *z, const int key_idx, const unsigned char *digest); +keystore_key_t* key_recover(keystore_key_t *key, const unsigned char *signature, const unsigned char *digest); +int key_from_public(keystore_key_t *key); +int key_from_private(keystore_key_t *key); #endif // _LIBSWARM_SIGN_H diff --git a/src/soc.c b/src/soc.c @@ -2,6 +2,7 @@ #include "keccak-tiny.h" +#include "keystore.h" #include "swarm.h" #include "soc.h" @@ -66,3 +67,44 @@ unsigned char* soc_serialize(const soc_chunk_t *chunk, unsigned char *z, size_t return z; } + + +// must be minimum 96 bytes long +int soc_digest(const soc_chunk_t *chunk, unsigned char *z) { + int r; + int crsr; + unsigned char *p; + + p = z + SWARM_WORD_SIZE; + crsr = 0; + memcpy(p + crsr, chunk->identifier, SWARM_SOC_IDENTIFIER_SIZE); + crsr += SWARM_SOC_IDENTIFIER_SIZE; + memcpy(p + crsr, chunk->data.hash, SWARM_WORD_SIZE); + crsr += SWARM_WORD_SIZE; + + r = keccak_hash_btc(z, SWARM_WORD_SIZE, p, crsr); + if (r < 0) { + return 1; + } + + return 0; +} + +int soc_verify(soc_chunk_t *chunk) { + int r; + unsigned char b[96]; + keystore_key_t key; + keystore_key_t *key_r; + + r = soc_digest(chunk, b); + if (r != 0) { + return 1; + } + + key_r = key_recover(&key, chunk->signature, b); + if (key_r == NULL) { + return 1; + } + + return 0; +} diff --git a/src/soc.h b/src/soc.h @@ -1,7 +1,7 @@ #ifndef _LIBSWARM_SOC_H #define _LIBSWARM_SOC_H -#include "swarm.h" +#include "def.h" #include "chunk.h" #define SWARM_SOC_TOPIC_SIZE 20 @@ -16,6 +16,8 @@ typedef struct soc_chunk { int soc_identifier(char *z, const char *topic, const char *index); int soc_address(char *z, const char *identifier, const char *address); +int soc_digest(const soc_chunk_t* chunk, unsigned char *z); unsigned char* soc_serialize(const soc_chunk_t *chunk, unsigned char *z, size_t *sz); +int soc_verify(soc_chunk_t *chunk); #endif // _LIBSWARM_SOC_H diff --git a/test/check_chunk.c b/test/check_chunk.c @@ -0,0 +1,56 @@ +#include <check.h> +#include <stdlib.h> + +#include "common.h" +#include "hex.h" +#include "def.h" +#include "chunk.h" + + +START_TEST(check_chunk_verify) { + int r; + swarm_chunk_t chunk; + + hex2bin(HASH_OF_FOO, chunk.hash); + memset(chunk.span, 0, SWARM_DATA_LENGTH_TYPESIZE); + chunk.span[0] = 3; + chunk.payload = "foo"; + chunk.payload_sz = 3; + + r = chunk_verify(&chunk); + ck_assert_int_eq(r, 0); + + chunk.span[0] = 4; + r = chunk_verify(&chunk); + ck_assert_int_eq(r, 1); +} +END_TEST + + +Suite * common_suite(void) { + Suite *s; + TCase *tc; + + s = suite_create("chunk"); + tc = tcase_create("core"); + tcase_add_test(tc, check_chunk_verify); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) { + int n_fail; + + Suite *s; + SRunner *sr; + + s = common_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_VERBOSE); + n_fail = srunner_ntests_failed(sr); + srunner_free(sr); + + return (n_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/test/check_keystore.c b/test/check_keystore.c @@ -44,10 +44,31 @@ START_TEST(check_keystore_getput) { } END_TEST +START_TEST(check_keystore_key_generate) { + int r; + keystore_key_t key; + + unsigned char public_key_check[SWARM_PUBLIC_KEY_SIZE]; + unsigned char label_check[SWARM_ADDRESS_SIZE]; + + hex2bin(TEST_PRIVATE_KEY, key.pk); + r = key_from_private(&key); + ck_assert_int_eq(r, 0); + + hex2bin(TEST_PUBLIC_KEY, public_key_check); + ck_assert_mem_eq(key.pubk, public_key_check, SWARM_PUBLIC_KEY_SIZE); + + hex2bin(TEST_ADDRESS, label_check); + ck_assert_mem_eq(key.label, label_check, SWARM_ADDRESS_SIZE); +} +END_TEST + START_TEST(check_keystore_sign) { int r; keystore_t keystore; keystore_key_t key; + keystore_key_t key_recovered; + keystore_key_t *key_recovered_returned; struct block_generator bg; unsigned char signature[SWARM_SIGNATURE_SIZE]; unsigned char *signature_returned; @@ -66,11 +87,12 @@ START_TEST(check_keystore_sign) { ck_assert_mem_eq(signature, signature_returned, sizeof(keystore_key_t)); - r = signature_recover_compact(signature, public_key, digest); - ck_assert_int_eq(r, 0); + key_recovered_returned = key_recover(&key_recovered, signature, digest); + ck_assert_ptr_nonnull(key_recovered_returned); hex2bin(TEST_PUBLIC_KEY, public_key_check); - ck_assert_mem_eq(public_key, public_key_check, SWARM_PUBLIC_KEY_SIZE); + ck_assert_mem_eq(key_recovered.pubk, public_key_check, SWARM_PUBLIC_KEY_SIZE); + ck_assert_mem_eq(key_recovered.pubk, key_recovered_returned->pubk, SWARM_PUBLIC_KEY_SIZE); keystore_free(&keystore); } @@ -84,6 +106,7 @@ Suite * common_suite(void) { tc = tcase_create("core"); tcase_add_test(tc, check_keystore_init); tcase_add_test(tc, check_keystore_getput); + tcase_add_test(tc, check_keystore_key_generate); tcase_add_test(tc, check_keystore_sign); suite_add_tcase(s, tc); diff --git a/test/check_soc.c b/test/check_soc.c @@ -5,6 +5,7 @@ #include "hex.h" #include "common.h" #include "def.h" +#include "keystore.h" START_TEST(check_soc_identifier) { @@ -22,6 +23,7 @@ START_TEST(check_soc_identifier) { } END_TEST + START_TEST(check_soc_address) { int i; int r; @@ -37,6 +39,42 @@ START_TEST(check_soc_address) { } END_TEST + +START_TEST(check_soc_digest) { + soc_chunk_t chunk; + int i; + int r; + char out[96]; + + r = soc_digest(&chunk, out); + ck_assert_int_eq(r, 0); +} +END_TEST + + +START_TEST(check_soc_verify) { + int r; + soc_chunk_t chunk; + keystore_key_t key; + keystore_key_t *key_returned; + struct block_generator bg; + + bg.v = 0; + bg.m = 256; + + hex2bin("TEST_PRIVATE_KEY", key.pk); + r = key_from_private(&key); + ck_assert_int_eq(r, 0); + + *(chunk.signature+64) = 0x01; + r = soc_verify(&chunk); + ck_assert_int_eq(r, 0); + + //key_returned = key_recover(&key, chunk.signature, digest); +} +END_TEST + + START_TEST(check_soc_serialize) { soc_chunk_t soc_chunk; long long span; @@ -83,6 +121,8 @@ Suite * common_suite(void) { tc = tcase_create("core"); tcase_add_test(tc, check_soc_identifier); tcase_add_test(tc, check_soc_address); + tcase_add_test(tc, check_soc_digest); + tcase_add_test(tc, check_soc_verify); tcase_add_test(tc, check_soc_serialize); suite_add_tcase(s, tc); diff --git a/test/common.c b/test/common.c @@ -36,32 +36,3 @@ void keystore_free(keystore_t *keystore) { free(keystore->keys); } -int signature_recover_compact(const unsigned char *signature, unsigned char *public_key, unsigned char *digest) { - int r; - size_t public_key_sz; - - secp256k1_context *ecctx; - secp256k1_ecdsa_recoverable_signature signature_o; - secp256k1_pubkey public_key_o; - - - r = secp256k1_ecdsa_recoverable_signature_parse_compact(ecctx, &signature_o, signature, (int)*(signature+64)); - if (r == 0) { - return 1; - } - - r = secp256k1_ecdsa_recover(ecctx, &public_key_o, &signature_o, digest); - if (r == 0) { - return 1; - } - - public_key_sz = SWARM_PUBLIC_KEY_SIZE; - r = secp256k1_ec_pubkey_serialize(ecctx, public_key, &public_key_sz, &public_key_o, SECP256K1_EC_UNCOMPRESSED); - if (r == 0) { - return 1; - } - if (public_key_sz != SWARM_PUBLIC_KEY_SIZE) { - return 1; - } - return 0; -} diff --git a/test/common.h b/test/common.h @@ -17,4 +17,3 @@ int block_generate(struct block_generator *bg, char *buf, size_t l); keystore_t* keystore_init(keystore_t *keystore); void keystore_free(keystore_t *keystore); -int signature_recover_compact(const unsigned char *signature, unsigned char *public_key, unsigned char *digest);