Base58 Kodierung/Dekodierung in C

Im Folgenden meine Beispielimplementierungen von Base58 Kodierung und Dekodierung.

Base58 mit LibTomMath

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <tommath.h>

static char _b58_alphabet[]="123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";

char *base58_encode(mp_int *n)
{
	static char encoded[256];
	int i, p=sizeof(encoded)-1;
	unsigned long base, mod;
	base=strlen(_b58_alphabet);	/* sizeof is 59, not 58 */
	for(encoded[p--]=0; ((i=mp_cmp_d(n, base))==MP_GT)||(i==MP_EQ); ) {
		mp_div_d(n, base, n, &mod);
		encoded[p--]=_b58_alphabet[mod];
		if(p==0) {
			return NULL;	/* string buffer overflow */
		}
	}
	if((i=mp_get_int(n)) > 0) {
		encoded[p]=_b58_alphabet[i];
	}
	return &encoded[p];
}

ssize_t strpos(char *haystack, char needle)
{
	char *p;
	for(p=haystack; *p != 0; p++) {
		if(*p == needle) {
			return (p-haystack);
		}
	}
	return -1;	/* not found */
}

int base58_decode(const char *s, mp_int *ret)
{
	size_t base=strlen(_b58_alphabet);
	ssize_t i, k;
	mp_int a, m;
	if(mp_init_multi(&a, &m, NULL) != MP_OKAY) {
		return -1;
	}
	mp_set(ret, 0);
	mp_set(&m, 1);
	for(i=strlen(s)-1; i>=0; i--) {
		mp_copy(&m, &a);
		if((k=strpos(_b58_alphabet, s[i])) < 0) {
			mp_clear_multi(&a, &m, NULL);
			return -1;	/* illegal char in string */
		}
		mp_mul_d(&a, k, &a);
		mp_add(&a, ret, ret);
		mp_mul_d(&m, base, &m);
	}
	mp_clear_multi(&a, &m, NULL);
	return 0;
}

int main(int argc, char **argv)
{
	char *s=NULL;
	mp_int n, q;
	int ret;
	char buf[256];
	if((ret=mp_init_multi(&n, &q, NULL)) != MP_OKAY) {
		printf("bignum alloc failed\n");
		return 1;
	}
	mp_read_radix(&n, "7ffffffffffffffff", 16);
	s=base58_encode(&n);
	printf("result=%s\n", s);
	base58_decode(s, &q);
	mp_toradix(&q, buf, 16);
	printf("result=%s\n", buf);
	mp_clear_multi(&n, &q, NULL);
	return 0;
}

To compile, you also need libtommath

Base58 mit OpenSSL

/* gcc base58.c -lcrypto */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "base58.h"
//#include <openssl/bn.h>

static char _b58_alphabet[]="123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";

int strpos(char *haystack, char needle);

char *base58_encode(BIGNUM *n)
{
	static char encoded[256];
	int i, p=sizeof(encoded)-1;
	BN_ULONG base, mod;
	BIGNUM *bb=NULL;

	if ((bb=BN_new()) == NULL) {
		return NULL;
	}
	base=strlen(_b58_alphabet);	/* sizeof is 59, not 58 */
	BN_set_word(bb, base);
	for (encoded[p--]=0; BN_cmp(n, bb) >= 0; ) {
		mod=BN_div_word(n, base);
		encoded[p--]=_b58_alphabet[mod];
		if (p==0) {
			return NULL;	/* string buffer overflow */
		}
	}
	if ((i=BN_get_word(n)) > 0) {
		encoded[p]=_b58_alphabet[i];
	}
	BN_free(bb);
	return &encoded[p];
}

int strpos(char *haystack, char needle)
{
	char *p;

	for (p=haystack; *p != 0; p++) {
		if (*p == needle) {
			return (p-haystack);
		}
	}
	return -1;	/* not found */
}

/* in case of error, memory is not freed yet */
BIGNUM *base58_decode(const char *s)
{
	int i, k, base=strlen(_b58_alphabet);
	BIGNUM *a, *m, *ret;

	if ((ret=BN_new())==NULL||(a=BN_new())==NULL||(m=BN_new())==NULL) {
		return NULL;
	}
	BN_set_word(ret, 0);
	BN_set_word(m, 1);
	for (i=strlen(s)-1; i>=0; i--) {
		BN_copy(a, m);
		if ((k=strpos(_b58_alphabet, s[i])) < 0) {
			BN_free(a);
			BN_free(m);
			BN_free(ret);
			return NULL;	/* illegal char in string */
		}
		BN_mul_word(a, k);
		BN_add(ret, ret, a);
		BN_mul_word(m, base);
	}
	BN_free(a);
	BN_free(m);
	return ret;
}

int main(int argc, char **argv)
{
	char *s=NULL;
	BIGNUM *n=NULL, *q=NULL;

	if ((n=BN_new()) == NULL) {
		printf("bignum alloc failed\n");
		return 1;
	}
//	BN_dec2bn(&n, "12345678901234567890");
	BN_hex2bn(&n, "fabb88b1152463b562317a1ac415043abc136c7d565cb61d21157311a33aeff8");
	s=base58_encode(n);
	printf("result=%s\n", s);
	q=base58_decode(s);
	s=BN_bn2hex(q);
	printf("result=%s\n", s);
	BN_free(n);
	return 0;
}