Added multibase and cid

xethyrion-master
John Jones 2016-11-13 21:01:51 -05:00
parent 9e303ef810
commit 02c5552cd6
17 changed files with 515 additions and 12 deletions

View File

@ -3,20 +3,24 @@ DEBUG = true
export DEBUG
all:
cd cid; make all;
cd cmd; make all;
cd commands; make all;
cd core; make all;
cd multibase; make all;
cd os; make all;
cd repo; make all;
cd test; make all;
cd thirdparty; make all;
cd test; make all;
clean:
cd cid; make clean;
cd cmd; make clean;
cd commands; make clean;
cd core; make clean;
cd multibase; make clean;
cd os; make clean;
cd repo; make clean;
cd test; make clean;
cd thirdparty; make clean;
cd test; make clean;

18
cid/Makefile Normal file
View File

@ -0,0 +1,18 @@
CC = gcc
CFLAGS = -O0 -I../include -I../../c-libp2p/include -I../../c-multihash/include
ifdef DEBUG
CFLAGS += -g3
endif
LFLAGS =
DEPS =
OBJS = cid.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
all: $(OBJS)
clean:
rm -f *.o

137
cid/cid.c Normal file
View File

@ -0,0 +1,137 @@
/**
* Content ID
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ipfs/cid/cid.h"
#include "libp2p/crypto/encoding/base58.h"
#include "ipfs/multibase/multibase.h"
#include "mh/multihash.h"
/**
* Create a new CID based on the given hash
* @param version the version
* @param hash the multihash
* @param hash_length the length of the multihash in bytes
* @param codec the codec to be used (NOTE: For version 0, this should be CID_PROTOBUF)
* @param cid where to put the results
* @returns true(1) on success
*/
int cid_new(int version, unsigned char* hash, size_t hash_length, const char codec, struct Cid* cid) {
// allocate memory
cid->hash = malloc(sizeof(unsigned char) * hash_length);
if (cid->hash == NULL)
return 0;
// assign values
cid->version = version;
cid->codec = codec;
memcpy(cid->hash, hash, hash_length);
cid->hash_length = hash_length;
return 1;
}
/***
* Free the resources from a Cid
* @param cid the struct
* @returns 1
*/
int cid_free(struct Cid* cid) {
if (cid->hash != NULL)
free(cid->hash);
return 1;
}
/***
* Fill a Cid struct based on a base 58 encoded string
* @param incoming the string
* @param incoming_size the size of the string
* @cid the Cid struct to fill
* @return true(1) on success
*/
int cid_decode_from_string(const unsigned char* incoming, size_t incoming_length, struct Cid* cid) {
int retVal = 0;
if (incoming_length < 2)
return 0;
// is this a sha_256 multihash?
if (incoming_length == 46 && incoming[0] == 'Q' && incoming[1] == 'm') {
size_t hash_length = libp2p_crypto_encoding_base58_decode_size(incoming_length);
unsigned char hash[hash_length];
unsigned char* ptr = hash;
retVal = libp2p_crypto_encoding_base58_decode(incoming, incoming_length, &ptr, &hash_length);
if (retVal == 0)
return 0;
// now we have the hash, build the object
return cid_new(0, hash, hash_length, CID_PROTOBUF, cid);
}
// TODO: finish this
/*
// it wasn't a sha_256 multihash, try to decode it using multibase
size_t buffer_size = multibase_decode_size(incoming_length);
if (buffer_size == 0)
return 0;
unsigned char buffer[buffer_size];
memset(buffer, 0, buffer_size);
retVal = multibase_decode(incoming, incoming_length, buffer, buffer_size, &buffer_size);
if (retVal == 0)
return 0;
return cid_cast(buffer, buffer_size, cid);
*/
return 0;
}
/***
* Turn a multibase decoded string of bytes into a Cid struct
* @param incoming the multibase decoded array
* @param incoming_size the size of the array
* @param cid the Cid structure to fill
*/
int cid_cast(unsigned char* incoming, size_t incoming_size, struct Cid* cid) {
// this is a multihash
if (incoming_size == 34 && incoming[0] == 18 && incoming[1] == 32) {
cid->hash_length = mh_multihash_length(incoming, incoming_size);
cid->codec = CID_PROTOBUF;
cid->version = 0;
// allocate memory for hash
cid->hash = malloc(cid->hash_length);
if (cid->hash == NULL)
return 0;
mh_multihash_digest(incoming, incoming_size, &cid->hash, &cid->hash_length);
return 1;
}
/*
*TODO: Implement this
// This is not a multihash. Try to peel the information out of the bytes
// first the version
int pos = 0, retVal = 0;
int num_bytes = 0;
retVal = varint_to_int(&incoming[pos], &cid->version, &num_bytes);
if (retVal == 0)
return 0;
pos = num_bytes;
// now the codec
retVal = varint_to_int(&incoming[pos], &cid->codec, &num_bytes);
if (retVal == 0)
return 0;
pos += num_bytes;
// now what is left
cid->hash_length = incoming_size - pos;
// TODO: allocate memory
memcpy(cid->hash, &incoming[pos], cid->hash_length);
*/
return 0;
}

62
include/ipfs/cid/cid.h Normal file
View File

@ -0,0 +1,62 @@
/***
* A content id
*/
#ifndef __IPFS_CID_CID_H
#define __IPFS_CID_CID_H
#define CID_PROTOBUF 0x70
#define CID_CBOR 0x71
#define CID_RAW 0x72
#define CID_JSON 0x73
#define CID_ETHEREUM_BLOCK 0x90
#define CID_ETHEREUM_TX 0x91
#define CID_BITCOIN_BLOCK 0xb0
#define CID_BITCOIN_TX 0xb1
#define CID_ZCASH_BLOCK 0xc0
#define CID_ZCASH_TX 0xc1
struct Cid {
int version;
char codec;
unsigned char* hash; // a multihash
size_t hash_length;
};
/**
* Create a new CID based on the given hash
* @param version the version
* @param hash the multihash
* @param hash_length the length of the multihash in bytes
* @param codec the codec to be used (NOTE: For version 0, this should be CID_PROTOBUF)
* @param cid where to put the results
* @returns true(1) on success
*/
int cid_new(int version, unsigned char* hash, size_t hash_length, const char codec, struct Cid* cid);
/***
* Free the resources from a Cid
* @param cid the struct
* @returns 1
*/
int cid_free(struct Cid* cid);
/***
* Fill a Cid struct based on a base 58 encoded string
* @param incoming the string
* @param incoming_size the size of the string
* @cid the Cid struct to fill
* @return true(1) on success
*/
int cid_decode_from_string(const unsigned char* incoming, size_t incoming_length, struct Cid* cid);
/***
* Turn a multibase decoded string of bytes into a Cid struct
* @param incoming the multibase decoded array
* @param incoming_size the size of the array
* @param cid the Cid structure to fill
*/
int cid_cast(unsigned char* incoming, size_t incoming_size, struct Cid* cid);
#endif

View File

@ -0,0 +1,47 @@
#include <stdio.h>
#ifndef __IPFS_MULTIBASE_MULTIBASE_H__
#define __IPFS_MULTIBASE_MULTIBASE_H__
// the first digit of data, to determine the encoding used or using
#define MULTIBASE_BASE1 '1'
#define MULTIBASE_BASE2 '0'
#define MULTIBASE_BASE8 '7'
#define MULTIBASE_BASE10 '9'
#define MULTIBASE_BASE16 'f'
#define MULTIBASE_BASE58_FLICKR 'Z'
#define MULTIBASE_BASE58_BTC 'z'
/**
* Encode data in multibase format
* @param base the format to use (i.e. MULTIBASE_BASE58_BTC)
* @param incoming the data to encode
* @param incoming_length the length of the data to encode
* @param results where to put the results
* @param results_max_length the size of the results buffer
* @param results_length the size of the results after being encoded
* @returns true(1) on success
*/
int multibase_encode(const char base, const unsigned char* incoming, size_t incoming_length, unsigned char* results, size_t results_max_length, size_t* results_length);
/***
* Calculates the size of the buffer neccessary to encode the incoming byte array
* @param base the encoding to use
* @param incoming the incoming array of bytes
* @param incoming_length the length of the array in bytes
* @returns the appropriate size of the buffer
*/
int multibase_encode_size(const char base, const unsigned char* incoming, size_t incoming_length);
/**
* Decode data that was encoded in multibase format
* @param incoming the data to decode
* @param incoming_length the length of the data to decode
* @param results where to put the results
* @param results_max_length the size of the results buffer
* @param results_length the size of the results after being encoded
* @returns true(1) on success
*/
int multibase_decode(const unsigned char* incoming, size_t incoming_length, unsigned char* results, size_t results_max_length, size_t* results_length);
#endif

14
include/ipfs/node/node.h Normal file
View File

@ -0,0 +1,14 @@
/**
* An implementation of an IPFS node
* Copying the go-ipfs-node project
*/
#include <stdint.h>
struct Link {
char* name;
uint64_t size;
struct Cid cid; // content id
};

18
multibase/Makefile Normal file
View File

@ -0,0 +1,18 @@
CC = gcc
CFLAGS = -O0 -I../include -I../../c-libp2p/include -I../../c-multihash/include
ifdef DEBUG
CFLAGS += -g3
endif
LFLAGS =
DEPS =
OBJS = multibase.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
all: $(OBJS)
clean:
rm -f *.o

113
multibase/multibase.c Normal file
View File

@ -0,0 +1,113 @@
#include <stdlib.h>
#include <string.h>
#include "ipfs/multibase/multibase.h"
#include "libp2p/crypto/encoding/base58.h"
#include "libp2p/crypto/encoding/base16.h"
/**
* Encode data in multibase format. NOTE: currently only supports MULTIBASE_BASE58_BTC and MULTIBASE_BASE16
* @param base the format to use (i.e. MULTIBASE_BASE58_BTC)
* @param incoming the data to encode
* @param incoming_length the length of the data to encode
* @param results where to put the results
* @param results_max_length the size of the results buffer
* @param results_length the size of the results after being encoded
* @returns true(1) on success
*/
int multibase_encode(const char base, const unsigned char* incoming, size_t incoming_length, unsigned char* results, size_t results_max_length, size_t* results_length) {
*results_length = results_max_length;
int retVal = 0;
switch (base) {
case (MULTIBASE_BASE58_BTC):
retVal = libp2p_crypto_encoding_base58_encode(incoming, incoming_length, &results, results_length);
break;
case(MULTIBASE_BASE16):
retVal = libp2p_crypto_encoding_base16_encode(incoming, incoming_length, results, results_length);
break;
default: // unsupported format
return 0;
}
// check to see if there was a problem
if (retVal == 0)
return 0;
// we have the hash, now add the code to the first byte (if there is room)
if (*results_length >= results_max_length) { // It could be equal, but should never be greater. But just in case.
return 0; // buffer isn't big enough
}
memcpy(&results[1], results, *results_length);
results[0] = base;
*results_length += 1;
return 1;
}
/***
* Calculates the size of the buffer neccessary to encode the incoming byte array
* @param base the encoding to use
* @param incoming the incoming array of bytes
* @param incoming_length the length of the array in bytes
* @returns the appropriate size of the buffer
*/
int multibase_encode_size(const char base, const unsigned char* incoming, size_t incoming_length) {
switch (base) {
case (MULTIBASE_BASE58_BTC):
return libp2p_crypto_encoding_base58_encode_size(incoming_length) + 1;
case (MULTIBASE_BASE16):
return libp2p_crypto_encoding_base16_encode_size(incoming_length);
}
return 0;
}
/**
* Decode data that was encoded in multibase format
* @param incoming the data to decode
* @param incoming_length the length of the data to decode
* @param results where to put the results
* @param results_max_length the size of the results buffer
* @param results_length the size of the results after being encoded
* @returns true(1) on success
*/
int multibase_decode(const unsigned char* incoming, size_t incoming_length, unsigned char* results, size_t results_max_length, size_t* results_length) {
*results_length = results_max_length;
int retVal = 0;
const char base = incoming[0];
switch (base) {
case (MULTIBASE_BASE58_BTC):
retVal = libp2p_crypto_encoding_base58_decode(&incoming[1], incoming_length - 1, &results, results_length);
break;
case(MULTIBASE_BASE16):
retVal = libp2p_crypto_encoding_base16_decode(&incoming[1], incoming_length - 1, results, results_length);
break;
default: // unsupported format
return 0;
}
// check to see if there was a problem
if (retVal == 0)
return 0;
return 1;
}
/***
* Calculates the size of the buffer neccessary to decode the incoming byte array
* @param base the encoding to use
* @param incoming the incoming array of bytes
* @param incoming_length the length of the array in bytes
* @returns the appropriate size of the buffer
*/
int multibase_decode_size(const char base, const unsigned char* incoming, size_t incoming_length) {
switch (base) {
case (MULTIBASE_BASE58_BTC):
return libp2p_crypto_encoding_base58_decode_size(incoming_length) + 1;
case (MULTIBASE_BASE16):
return libp2p_crypto_encoding_base16_decode_size(incoming_length);
}
return 0;
}

7
node/node.c Normal file
View File

@ -0,0 +1,7 @@
/**
* An implementation of an IPFS node
* Copying the go-ipfs-node project
*/
#include "ipfs/node/node.h"

View File

@ -7,7 +7,7 @@ endif
LFLAGS =
DEPS = config.h datastore.h identity.h
OBJS = config.o
OBJS = config.o identity.o bootstrap_peers.o datastore.o gateway.o addresses.o swarm.o peer.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

View File

@ -23,7 +23,7 @@ int repo_config_identity_new(struct Identity* identity, unsigned long num_bits_f
if (num_bits_for_keypair < 1024)
return 0;
// generate the private key (& public)
if (!crypto_rsa_generate_keypair( &(identity->private_key), num_bits_for_keypair))
if (!libp2p_crypto_rsa_generate_keypair( &(identity->private_key), num_bits_for_keypair))
return 0;
// now the private key (in DER format) is in identity->private_key->der;

View File

@ -30,9 +30,9 @@ int repo_config_write_config_file(char* full_filename, struct RepoConfig* config
fprintf(out_file, " \"PeerID\": \"%s\",\n", config->identity.peer_id);
// TODO: print correct format of private key
// first base 64 it
size_t encoded_size = base64_encode_length(config->identity.private_key.der, config->identity.private_key.der_length);
size_t encoded_size = libp2p_crypto_encoding_base64_encode_size(config->identity.private_key.der_length);
unsigned char encoded_buffer[encoded_size + 1];
int retVal = base64_encode(config->identity.private_key.der, config->identity.private_key.der_length, encoded_buffer, encoded_size, &encoded_size);
int retVal = libp2p_crypto_encoding_base64_encode(config->identity.private_key.der, config->identity.private_key.der_length, encoded_buffer, encoded_size, &encoded_size);
if (retVal == 0)
return 0;
encoded_buffer[encoded_size] = 0;

View File

@ -1,13 +1,13 @@
CC = gcc
CFLAGS = -O0 -I../include -I../../c-libp2p/include -g3
LFLAGS = -L../../c-libp2p -lp2p
DEPS = cmd/ipfs/test_init.h repo/test_repo_bootstrap_peers.h repo/test_repo_config.h repo/test_repo_identity.h
CFLAGS = -O0 -I../include -I../../c-libp2p/include -I../../c-multihash/include -g3
LFLAGS = -L../../c-libp2p -L../../c-multihash -lp2p -lm -lmultihash
DEPS = cmd/ipfs/test_init.h repo/test_repo_bootstrap_peers.h repo/test_repo_config.h repo/test_repo_identity.h cid/test_cid.h
OBJS = testit.o ../cmd/ipfs/init.o ../commands/argument.o ../commands/command_option.o \
../commands/command.o ../commands/cli/parse.o ../core/builder.o ../repo/fsrepo/fs_repo.o \
../repo/fsrepo/fs_repo.o ../repo//config/config.o ../os/utils.o ../repo/config/identity.o \
../repo/config/bootstrap_peers.o ../repo/config/datastore.o ../repo/config/gateway.o \
../repo/config/addresses.o ../repo/config/swarm.o ../repo/config/peer.o \
../thirdparty/ipfsaddr/ipfs_addr.o
../thirdparty/ipfsaddr/ipfs_addr.o ../cid/cid.o ../multibase/multibase.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

79
test/cid/test_cid.h Normal file
View File

@ -0,0 +1,79 @@
#include <string.h>
#include "mh/hashes.h"
#include "mh/multihash.h"
#include "ipfs/cid/cid.h"
#include "ipfs/multibase/multibase.h"
#include "libp2p/crypto/hashing/sha256.h"
int test_cid_new_free() {
struct Cid cid;
const unsigned char* hash = "ABC123";
int retVal = cid_new(0, (unsigned char*)hash, strlen((char*)hash), CID_PROTOBUF, &cid);
if (retVal == 0)
return 0;
if (cid.version != 0)
return 0;
if (cid.codec != CID_PROTOBUF)
return 0;
if (cid.hash_length != strlen((char*)hash))
return 0;
if (strncmp((char*)cid.hash, (char*)hash, 6) != 0)
return 0;
return cid_free(&cid);
}
/***
* Test sending a multibase encoded multihash into cid_cast method
* that should return a Cid struct
*/
int test_cid_cast_multihash() {
// first, build a multihash
char* string_to_hash = "Hello, World!";
unsigned char hashed[32];
memset(hashed, 0, 32);
// hash the string
libp2p_crypto_hashing_sha256(string_to_hash, strlen(string_to_hash), hashed);
size_t multihash_size = mh_new_length(MH_H_SHA2_256, 32);
unsigned char multihash[multihash_size];
memset(multihash, 0, multihash_size);
unsigned char* ptr = multihash;
int retVal = mh_new(ptr, MH_H_SHA2_256, hashed, 32);
if (retVal < 0)
return 0;
// now call cast
struct Cid cid;
retVal = cid_cast(multihash, multihash_size, &cid);
if (retVal == 0)
return 0;
// check results
if (cid.version != 0)
return 0;
if (cid.hash_length != 32)
return 0;
if (cid.codec != CID_PROTOBUF)
return 0;
if (strncmp(hashed, cid.hash, 32) != 0)
return 0;
return 1;
}
int test_cid_cast_non_multihash() {
// this should turn a multibase encoded string into a cid struct
// first, build a multibase encoded string
// now call cast
// check results
return 0;
}

View File

@ -29,9 +29,9 @@ int test_repo_config_identity_new() {
// test this key
int test_repo_config_identity_private_key() {
const char* priv_b64 = "CAASpwkwggSjAgEAAoIBAQDTDJBWjDzS/HxDNOHazvzH2bu9CPMVHUrrvKRdBUM5ansL6/CC3MVZ6HVm4O6QHRapN6EF2CbrTgI4KBOXIL125Xo8MlROnyfXYk3O5q2tgwL/MbW8kXjtkyCfBak7MUoLOdLU7Svg0gkl3l+uDAiDcCLnwJVcFfq9ch6z4wMOhYJqE5dtx0uXxn6IuKWl1B69FTvBXCc0thw8Rw54b941FDcsBH5ttV9mRNCJym3poZ5qalNgXlxoIIB+PUx5QD+aq7KMJdpAX8HkapBntCOahP/QUceRmma0grlZLeYkH6/oi/hIrM6se3KUZ+F6tBuDFys8UAZy/X2BCUbKjbxtAgMBAAECggEANWfQfpYuLhXGPBt9q6kFPm1SnJtPJ+CpvM2XqhJS2IyhZnrl+bd0GTRBwS7aL42s1lVFYf04nAK5fQxnKK8YQqX/MIxr2RldM5ukpN6qxGWKtJkXrAgD2dqJPrRoBpqKahzPxSHfIJ0Fw5dqDtjsrpYJvyt0oEDPmnDuZAbmFx4sJqnesPNhKxtRMBx1+yxGVuRVJjHcqAgqPqwNiuoMEaYMY+G9yzT6vza8ovCpbX7BBIgM5fAT9PD8TBG//Vu9THvj/ZomiVG2qv6RL0qQyVb+DUzPZz1amBsSvahtXCl72jA3JwAZ943RxSR66P934S0ashkVwLUi46z/EAbJ4QKBgQDojGIO07BEVL2+7VxlGL9XGZQp4Y3qlhh2zDDQGwkCq/KQ+BdNYWitPwqRl9GqFLgpmeQIhyHTOa/IThx+AXGKVQ24ROH+skUs4IbO6R3qY7BKtb5lkZE/Yln09x70BBngUYAzh/rtnsXO3cl1x2XDDqUbCwlGcDAs8Jh/6UnvQwKBgQDoVSQs7Uq9MJCGIUM2bixX89tHzSxq5mn9wMD3/XRVfT5Ua8YkYBuzcmlcT39N7L5BwuyFqX3Vi7lv/Ya/qaQP6XkrZ8W1OAaTlYewfE5ZgknJqSpXcNWhABKeNmqndvqyQ/8HNCv/j8AdraGB2DGO57Xso5J0CQ43W/U9+QIyjwKBgHLL2hw3o+wXaRO3WMUPUmVM2zdRgR0suybp5a7Vqb0H5NZrohUw4NulIzJ8H6Q2VjMzJL6Q9sGu2HepF6ecTtBa7ErqtiVlG4Dr1aCOs5XhYEWBMlwxX+JKSt4Cn+UVoTB7Cy5lEhn7JurX0Xuy0ylXMWoIKKv89cs5eg6quzTBAoGAaq9eEztLjKCWXOE9SetBdYnG8aunb9cqaJlwgu/h0bfXPVDYBbAUSEyLURY4MQI7Q1tM3Pu9iqfEmUZj7/LoIV5mg6X9RX/alT6etk3+dF+9nlqN1OU9U9cCtZ/rTcb2y5EptJcidRH/eCFY/pTV/PcttOJPx/S4kHcroC+N8MUCgYEA6DA5QHxHfNN6Nxv+pEzy2DIxFe9RrBxS+KPBsra1C8jgdeMf4EmfU0Nox92V0q0bRrD5ztqQwSONI0hSRb1iiMWR6MuFnAFajUJfASjjIlZ6nIQjQslI7vjlvYyyHS/p/Codxap+yJlTLWwVEOXp2D9pWwiMq1xEyf0TH1BosvM=";
size_t decoded_len = base64_decode_length(priv_b64, strlen(priv_b64));
size_t decoded_len = libp2p_crypto_encoding_base64_decode_size(strlen(priv_b64));
char* out_buff = malloc(sizeof(char) * decoded_len);
base64_decode(priv_b64, strlen(priv_b64), out_buff, decoded_len, &decoded_len);
libp2p_crypto_encoding_base64_decode(priv_b64, strlen(priv_b64), out_buff, decoded_len, &decoded_len);
char str[decoded_len];
int j = 0;
for (int i = 0; i < decoded_len; i++) {

BIN
test/test_ipfs Executable file

Binary file not shown.

View File

@ -2,6 +2,7 @@
#include "repo/test_repo_identity.h"
#include "repo/test_repo_bootstrap_peers.h"
#include "cmd/ipfs/test_init.h"
#include "cid/test_cid.h"
int testit(const char* name, int (*func)(void)) {
printf("Testing %s...\n", name);
@ -14,6 +15,9 @@ int testit(const char* name, int (*func)(void)) {
}
int main(int argc, char** argv) {
testit("test_cid_new_free", test_cid_new_free);
testit("test_cid_cast_multihash", test_cid_cast_multihash);
testit("test_cid_cast_non_multihash", test_cid_cast_non_multihash);
testit("test_init_new_installation", test_init_new_installation);
testit("test_repo_config_init", test_repo_config_init);
testit("test_repo_config_write", test_repo_config_write);