├── .gitignore ├── README ├── all-tests.sh ├── base58.h ├── common.h ├── ec-priv.pem ├── ec-pub.pem ├── ec.h ├── endian.h ├── ex-address.c ├── ex-base58.c ├── ex-ec-keypair.c ├── ex-ecdsa-sign.c ├── ex-ecdsa-verify.c ├── ex-fixed-strings.c ├── ex-hashes.c ├── ex-integers.c ├── ex-message.txt ├── ex-signature.der ├── ex-tx-build.c ├── ex-tx-pack.c ├── ex-tx-sign.c ├── ex-vardata.c ├── ex-varints.c ├── ex-wif.c ├── hash.h ├── test.sh ├── tx.h └── varint.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *.o 4 | *.out 5 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Sample code from "Basic blockchain programming", a developer-oriented series about Bitcoin. 2 | 3 | http://davidederosa.com/basic-blockchain-programming/ 4 | -------------------------------------------------------------------------------- /all-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | OPENSSL_INCLUDE=/usr/local/opt/openssl/include/ 3 | for FILE in `ls *.c`; do 4 | TEST=${FILE%.*} 5 | 6 | echo === $TEST === 7 | echo 8 | ./test.sh $TEST 9 | echo 10 | done 11 | -------------------------------------------------------------------------------- /base58.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE58_H 2 | #define __BASE58_H 3 | 4 | #include 5 | #include 6 | #include "endian.h" 7 | #include "hash.h" 8 | 9 | static const char bbp_base58_alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 10 | 11 | char *bbp_base58(const uint8_t *bytes, size_t len) { 12 | size_t str_len; 13 | char *str; 14 | BN_CTX *ctx; 15 | BIGNUM *base, *x, *r; 16 | int i, j; 17 | 18 | str_len = len * 138 / 100 + 2; 19 | str = calloc(str_len, sizeof(char)); 20 | 21 | ctx = BN_CTX_new(); 22 | BN_CTX_start(ctx); 23 | 24 | base = BN_new(); 25 | x = BN_new(); 26 | r = BN_new(); 27 | BN_set_word(base, 58); 28 | BN_bin2bn(bytes, len, x); 29 | 30 | i = 0; 31 | while (!BN_is_zero(x)) { 32 | BN_div(x, r, x, base, ctx); 33 | str[i] = bbp_base58_alphabet[BN_get_word(r)]; 34 | ++i; 35 | } 36 | for (j = 0; j < len; ++j) { 37 | if (bytes[j] != 0x00) { 38 | break; 39 | } 40 | str[i] = bbp_base58_alphabet[0]; 41 | ++i; 42 | } 43 | bbp_reverse((uint8_t *)str, i); 44 | 45 | BN_clear_free(r); 46 | BN_clear_free(x); 47 | BN_free(base); 48 | BN_CTX_end(ctx); 49 | BN_CTX_free(ctx); 50 | 51 | return str; 52 | } 53 | 54 | char *bbp_base58check(const uint8_t *bytes, size_t len) { 55 | size_t check_len; 56 | uint8_t *check; 57 | uint8_t digest[32]; 58 | char *str; 59 | 60 | check_len = len + 4; 61 | check = calloc(check_len, sizeof(char)); 62 | 63 | bbp_hash256(digest, bytes, len); 64 | memcpy(check, bytes, len); 65 | memcpy(check + len, digest, 4); 66 | 67 | str = bbp_base58(check, check_len); 68 | free(check); 69 | 70 | return str; 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMON_H 2 | #define __COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "endian.h" 8 | 9 | void bbp_print_hex(const char *label, const uint8_t *v, size_t len) { 10 | size_t i; 11 | 12 | printf("%s: ", label); 13 | for (i = 0; i < len; ++i) { 14 | printf("%02x", v[i]); 15 | } 16 | printf("\n"); 17 | } 18 | 19 | uint8_t bbp_hex2byte(const char ch) { 20 | if ((ch >= '0') && (ch <= '9')) { 21 | return ch - '0'; 22 | } 23 | if ((ch >= 'a') && (ch <= 'f')) { 24 | return ch - 'a' + 10; 25 | } 26 | return 0; 27 | } 28 | 29 | void bbp_parse_hex(uint8_t *v, const char *str) { 30 | const size_t count = strlen(str) / 2; 31 | size_t i; 32 | 33 | for (i = 0; i < count; ++i) { 34 | const char hi = bbp_hex2byte(str[i * 2]); 35 | const char lo = bbp_hex2byte(str[i * 2 + 1]); 36 | 37 | v[i] = hi * 16 + lo; 38 | } 39 | } 40 | 41 | uint8_t *bbp_alloc_hex(const char *str, size_t *len) { 42 | const size_t count = strlen(str) / 2; 43 | size_t i; 44 | 45 | uint8_t *v = malloc(count); 46 | 47 | for (i = 0; i < count; ++i) { 48 | const char hi = bbp_hex2byte(str[i * 2]); 49 | const char lo = bbp_hex2byte(str[i * 2 + 1]); 50 | 51 | v[i] = hi * 16 + lo; 52 | } 53 | 54 | *len = count; 55 | 56 | return v; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /ec-priv.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BgUrgQQACg== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHQCAQEEIBYmB4PkCxZzFnNiKsilsEX8PqSvcPcn8/npK906HdxCoAcGBSuBBAAK 6 | oUQDQgAEggBuk5immG7aYf6RZ0w6EIw5lHW/HnOPGd/C2xHbHSgTDGs7KK75qcfn 7 | FD2sbPEsCbhETbYWeaux2G+FwDiljA== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /ec-pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEggBuk5immG7aYf6RZ0w6EIw5lHW/HnOP 3 | Gd/C2xHbHSgTDGs7KK75qcfnFD2sbPEsCbhETbYWeaux2G+FwDiljA== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /ec.h: -------------------------------------------------------------------------------- 1 | #ifndef __EC_H 2 | #define __EC_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | EC_KEY *bbp_ec_new_keypair(const uint8_t *priv_bytes) { 10 | EC_KEY *key; 11 | BIGNUM *priv; 12 | BN_CTX *ctx; 13 | const EC_GROUP *group; 14 | EC_POINT *pub; 15 | 16 | /* init empty OpenSSL EC keypair */ 17 | 18 | key = EC_KEY_new_by_curve_name(NID_secp256k1); 19 | 20 | /* set private key through BIGNUM */ 21 | 22 | priv = BN_new(); 23 | BN_bin2bn(priv_bytes, 32, priv); 24 | EC_KEY_set_private_key(key, priv); 25 | 26 | /* derive public key from private key and group */ 27 | 28 | ctx = BN_CTX_new(); 29 | BN_CTX_start(ctx); 30 | 31 | group = EC_KEY_get0_group(key); 32 | pub = EC_POINT_new(group); 33 | EC_POINT_mul(group, pub, priv, NULL, NULL, ctx); 34 | EC_KEY_set_public_key(key, pub); 35 | 36 | /* release resources */ 37 | 38 | EC_POINT_free(pub); 39 | BN_CTX_end(ctx); 40 | BN_CTX_free(ctx); 41 | BN_clear_free(priv); 42 | 43 | return key; 44 | } 45 | 46 | EC_KEY *bbp_ec_new_pubkey(const uint8_t *pub_bytes, size_t pub_len) { 47 | EC_KEY *key; 48 | const uint8_t *pub_bytes_copy; 49 | 50 | key = EC_KEY_new_by_curve_name(NID_secp256k1); 51 | pub_bytes_copy = pub_bytes; 52 | o2i_ECPublicKey(&key, &pub_bytes_copy, pub_len); 53 | 54 | return key; 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /endian.h: -------------------------------------------------------------------------------- 1 | #ifndef __ENDIAN_H 2 | #define __ENDIAN_H 3 | 4 | #include 5 | #include 6 | #include "common.h" 7 | 8 | typedef enum { 9 | BBP_BIG, 10 | BBP_LITTLE 11 | } bbp_endian_t; 12 | 13 | bbp_endian_t bbp_host_endian() { 14 | static const union { 15 | uint16_t i; 16 | uint8_t c[2]; 17 | } test = { 0x1234 }; 18 | 19 | return ((test.c[0] == 0x34) ? BBP_LITTLE : BBP_BIG ); 20 | } 21 | 22 | uint16_t bbp_swap16(uint16_t n) { 23 | return (n >> 8) | 24 | ((n & 0xff) << 8); 25 | } 26 | 27 | uint32_t bbp_swap32(uint32_t n) { 28 | return (n >> 24) | 29 | ((n & 0xff0000) >> 8) | 30 | ((n & 0xff00) << 8) | 31 | ((n & 0xff) << 24); 32 | } 33 | 34 | uint64_t bbp_swap64(uint64_t n) { 35 | return (n >> 56) | 36 | ((n & 0xff000000000000) >> 40) | 37 | ((n & 0xff0000000000) >> 24) | 38 | ((n & 0xff00000000) >> 8) | 39 | ((n & 0xff000000) << 8) | 40 | ((n & 0xff0000) << 24) | 41 | ((n & 0xff00) << 40) | 42 | ((n & 0xff) << 56); 43 | } 44 | 45 | uint16_t bbp_eint16(bbp_endian_t e, uint16_t n) { 46 | if (bbp_host_endian() == e) { 47 | return n; 48 | } 49 | return bbp_swap16(n); 50 | } 51 | 52 | uint32_t bbp_eint32(bbp_endian_t e, uint32_t n) { 53 | if (bbp_host_endian() == e) { 54 | return n; 55 | } 56 | return bbp_swap32(n); 57 | } 58 | 59 | uint64_t bbp_eint64(bbp_endian_t e, uint64_t n) { 60 | if (bbp_host_endian() == e) { 61 | return n; 62 | } 63 | return bbp_swap64(n); 64 | } 65 | 66 | void bbp_reverse(uint8_t *dst, size_t len) { 67 | size_t i; 68 | const size_t stop = len >> 1; 69 | for (i = 0; i < stop; ++i) { 70 | uint8_t *left = dst + i; 71 | uint8_t *right = dst + len - i - 1; 72 | const uint8_t tmp = *left; 73 | *left = *right; 74 | *right = tmp; 75 | } 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /ex-address.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "base58.h" 3 | #include "hash.h" 4 | 5 | int main() { 6 | uint8_t pub_bytes[33] = { 7 | 0x02, 8 | 0x82, 0x00, 0x6e, 0x93, 0x98, 0xa6, 0x98, 0x6e, 9 | 0xda, 0x61, 0xfe, 0x91, 0x67, 0x4c, 0x3a, 0x10, 10 | 0x8c, 0x39, 0x94, 0x75, 0xbf, 0x1e, 0x73, 0x8f, 11 | 0x19, 0xdf, 0xc2, 0xdb, 0x11, 0xdb, 0x1d, 0x28 12 | }; 13 | uint8_t address_bytes[21]; 14 | char *address; 15 | 16 | const char address_exp[] = "mqMi3XYqsPvBWtrJTk8euPWDVmFTZ5jHuK"; 17 | 18 | /* */ 19 | 20 | bbp_print_hex("pub", pub_bytes, sizeof(pub_bytes)); 21 | 22 | address_bytes[0] = 0x6f; 23 | bbp_hash160(address_bytes + 1, pub_bytes, 33); 24 | bbp_print_hex("hash160", address_bytes + 1, 20); 25 | 26 | address = bbp_base58check(address_bytes, 21); 27 | printf("address : %s\n", address); 28 | printf("address (exp): %s\n", address_exp); 29 | free(address); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /ex-base58.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "base58.h" 3 | 4 | int main() { 5 | uint8_t bytes[] = { 6 | 0x73, 0xb7, 0xb2, 0x1c, 0x26, 0xc1, 0x7b, 0x72, 7 | 0x24, 0xdb, 0x60, 0xff, 0x7d, 0xd7, 0xe4, 0xc6, 8 | 0x48, 0xf5, 0x6c, 0x70, 0x24, 0x4e, 0xa6, 0xc4, 9 | 0xb6, 0x94, 0x1c, 0x0c, 0xbd, 0x16, 0x8c, 0x30 10 | }; 11 | char *base58; 12 | 13 | const char base58_exp[] = "8niM7FzqQeaPANNtRwEtQGi37YRcFwx1UBZMX8214MVq"; 14 | 15 | /* */ 16 | 17 | base58 = bbp_base58(bytes, sizeof(bytes)); 18 | bbp_print_hex("hex", bytes, sizeof(bytes)); 19 | printf("base58 : %s\n", base58); 20 | printf("base58 (exp): %s\n", base58_exp); 21 | free(base58); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ex-ec-keypair.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "ec.h" 3 | 4 | int main() { 5 | uint8_t priv_bytes[32] = { 6 | 0x16, 0x26, 0x07, 0x83, 0xe4, 0x0b, 0x16, 0x73, 7 | 0x16, 0x73, 0x62, 0x2a, 0xc8, 0xa5, 0xb0, 0x45, 8 | 0xfc, 0x3e, 0xa4, 0xaf, 0x70, 0xf7, 0x27, 0xf3, 9 | 0xf9, 0xe9, 0x2b, 0xdd, 0x3a, 0x1d, 0xdc, 0x42 10 | }; 11 | 12 | EC_KEY *key; 13 | uint8_t priv[32]; 14 | uint8_t *pub; 15 | const BIGNUM *priv_bn; 16 | 17 | point_conversion_form_t conv_forms[] = { 18 | POINT_CONVERSION_UNCOMPRESSED, 19 | POINT_CONVERSION_COMPRESSED 20 | }; 21 | const char *conv_forms_desc[] = { 22 | "uncompressed", 23 | "compressed" 24 | }; 25 | int i; 26 | 27 | const char priv_exp[] = "16260783e40b16731673622ac8a5b045fc3ea4af70f727f3f9e92bdd3a1ddc42"; 28 | const char pub_exp[2][200] = { 29 | "0482006e9398a6986eda61fe91674c3a108c399475bf1e738f19dfc2db11db1d28130c6b3b28aef9a9c7e7143dac6cf12c09b8444db61679abb1d86f85c038a58c", 30 | "0282006e9398a6986eda61fe91674c3a108c399475bf1e738f19dfc2db11db1d28" 31 | }; 32 | 33 | /* create keypair */ 34 | 35 | key = bbp_ec_new_keypair(priv_bytes); 36 | if (!key) { 37 | puts("Unable to create keypair"); 38 | return -1; 39 | } 40 | bbp_print_hex("priv #1 ", priv_bytes, sizeof(priv)); 41 | 42 | /* get private key back from EC_KEY */ 43 | 44 | priv_bn = EC_KEY_get0_private_key(key); 45 | if (!priv_bn) { 46 | puts("Unable to decode private key"); 47 | return -1; 48 | } 49 | BN_bn2bin(priv_bn, priv); 50 | bbp_print_hex("priv #2 ", priv, sizeof(priv)); 51 | 52 | printf("priv (exp): %s\n", priv_exp); 53 | 54 | /* get encoded public key from EC_KEY in all conversion forms */ 55 | 56 | for (i = 0; i < sizeof(conv_forms) / sizeof(point_conversion_form_t); ++i) { 57 | size_t pub_len; 58 | uint8_t *pub_copy; 59 | 60 | EC_KEY_set_conv_form(key, conv_forms[i]); 61 | 62 | pub_len = i2o_ECPublicKey(key, NULL); 63 | pub = calloc(pub_len, sizeof(uint8_t)); 64 | 65 | /* pub_copy is needed because i2o_ECPublicKey alters the input pointer */ 66 | pub_copy = pub; 67 | if (i2o_ECPublicKey(key, &pub_copy) != pub_len) { 68 | puts("Unable to decode public key"); 69 | return -1; 70 | } 71 | 72 | printf("conversion form: %s\n", conv_forms_desc[i]); 73 | bbp_print_hex("pub ", pub, pub_len); 74 | printf("pub (exp): %s\n", pub_exp[i]); 75 | 76 | free(pub); 77 | } 78 | 79 | /* release keypair */ 80 | 81 | EC_KEY_free(key); 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /ex-ecdsa-sign.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "ec.h" 3 | #include "hash.h" 4 | 5 | int main() { 6 | uint8_t priv_bytes[32] = { 7 | 0x16, 0x26, 0x07, 0x83, 0xe4, 0x0b, 0x16, 0x73, 8 | 0x16, 0x73, 0x62, 0x2a, 0xc8, 0xa5, 0xb0, 0x45, 9 | 0xfc, 0x3e, 0xa4, 0xaf, 0x70, 0xf7, 0x27, 0xf3, 10 | 0xf9, 0xe9, 0x2b, 0xdd, 0x3a, 0x1d, 0xdc, 0x42 11 | }; 12 | const char message[] = "This is a very confidential message\n"; 13 | 14 | EC_KEY *key; 15 | uint8_t digest[32]; 16 | ECDSA_SIG *signature; 17 | uint8_t *der, *der_copy; 18 | size_t der_len; 19 | 20 | const char digest_exp[] = "4554813e91f3d5be790c7c608f80b2b00f3ea77512d49039e9e3dc45f89e2f01"; 21 | 22 | /* */ 23 | 24 | key = bbp_ec_new_keypair(priv_bytes); 25 | if (!key) { 26 | puts("Unable to create keypair"); 27 | return -1; 28 | } 29 | 30 | bbp_sha256(digest, (uint8_t *)message, strlen(message)); 31 | bbp_print_hex("digest ", digest, 32); 32 | printf("digest (exp): %s\n", digest_exp); 33 | 34 | signature = ECDSA_do_sign(digest, sizeof(digest), key); 35 | printf("r: %s\n", BN_bn2hex(signature->r)); 36 | printf("s: %s\n", BN_bn2hex(signature->s)); 37 | 38 | der_len = ECDSA_size(key); 39 | der = calloc(der_len, sizeof(uint8_t)); 40 | der_copy = der; 41 | i2d_ECDSA_SIG(signature, &der_copy); 42 | bbp_print_hex("DER-encoded", der, der_len); 43 | 44 | free(der); 45 | ECDSA_SIG_free(signature); 46 | EC_KEY_free(key); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /ex-ecdsa-verify.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "ec.h" 3 | #include "hash.h" 4 | 5 | int main() { 6 | uint8_t pub_bytes[33] = { 7 | 0x02, 8 | 0x82, 0x00, 0x6e, 0x93, 0x98, 0xa6, 0x98, 0x6e, 9 | 0xda, 0x61, 0xfe, 0x91, 0x67, 0x4c, 0x3a, 0x10, 10 | 0x8c, 0x39, 0x94, 0x75, 0xbf, 0x1e, 0x73, 0x8f, 11 | 0x19, 0xdf, 0xc2, 0xdb, 0x11, 0xdb, 0x1d, 0x28 12 | }; 13 | uint8_t der_bytes[] = { 14 | 0x30, 0x44, 0x02, 0x20, 0x2b, 0x2b, 0x52, 0x9b, 15 | 0xdb, 0xdc, 0x93, 0xe7, 0x8a, 0xf7, 0xe0, 0x02, 16 | 0x28, 0xb1, 0x79, 0x91, 0x8b, 0x03, 0x2d, 0x76, 17 | 0x90, 0x2f, 0x74, 0xef, 0x45, 0x44, 0x26, 0xf7, 18 | 0xd0, 0x6c, 0xd0, 0xf9, 0x02, 0x20, 0x62, 0xdd, 19 | 0xc7, 0x64, 0x51, 0xcd, 0x04, 0xcb, 0x56, 0x7c, 20 | 0xa5, 0xc5, 0xe0, 0x47, 0xe8, 0xac, 0x41, 0xd3, 21 | 0xd4, 0xcf, 0x7c, 0xb9, 0x24, 0x34, 0xd5, 0x5c, 22 | 0xb4, 0x86, 0xcc, 0xcf, 0x6a, 0xf2 23 | }; 24 | const char message[] = "This is a very confidential message\n"; 25 | 26 | EC_KEY *key; 27 | const uint8_t *der_bytes_copy; 28 | ECDSA_SIG *signature; 29 | uint8_t digest[32]; 30 | int verified; 31 | 32 | const char *r_exp = "2B2B529BDBDC93E78AF7E00228B179918B032D76902F74EF454426F7D06CD0F9"; 33 | const char *s_exp = "62DDC76451CD04CB567CA5C5E047E8AC41D3D4CF7CB92434D55CB486CCCF6AF2"; 34 | const char *digest_exp = "4554813e91f3d5be790c7c608f80b2b00f3ea77512d49039e9e3dc45f89e2f01"; 35 | 36 | /* */ 37 | 38 | key = bbp_ec_new_pubkey(pub_bytes, sizeof(pub_bytes)); 39 | if (!key) { 40 | puts("Unable to create keypair"); 41 | return -1; 42 | } 43 | 44 | der_bytes_copy = der_bytes; 45 | signature = d2i_ECDSA_SIG(NULL, &der_bytes_copy, sizeof(der_bytes)); 46 | printf("r : %s\n", BN_bn2hex(signature->r)); 47 | printf("r (exp): %s\n", r_exp); 48 | printf("s : %s\n", BN_bn2hex(signature->s)); 49 | printf("s (exp): %s\n", s_exp); 50 | 51 | bbp_sha256(digest, (uint8_t *)message, strlen(message)); 52 | bbp_print_hex("digest ", digest, 32); 53 | printf("digest (exp): %s\n", digest_exp); 54 | verified = ECDSA_do_verify(digest, sizeof(digest), signature, key); 55 | 56 | switch (verified) { 57 | case 1: 58 | puts("verified"); 59 | break; 60 | case 0: 61 | puts("not verified"); 62 | break; 63 | case -1: 64 | puts("library error"); 65 | break; 66 | } 67 | 68 | ECDSA_SIG_free(signature); 69 | EC_KEY_free(key); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /ex-fixed-strings.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | int main() { 4 | uint32_t n32 = 0x68f7a38b; 5 | char str[] = "FooBar"; 6 | size_t str_len = 10; 7 | uint16_t n16 = 0xee12; 8 | uint8_t ser[16]; 9 | 10 | const char ser_exp[] = "8ba3f768466f6f4261720000000012ee"; 11 | 12 | /* */ 13 | 14 | size_t str_real_len = strlen(str); 15 | size_t str_pad_len = str_len - str_real_len; 16 | 17 | *(uint32_t *)(ser) = bbp_eint32(BBP_LITTLE, n32); 18 | memcpy(ser + 4, str, str_real_len); 19 | if (str_pad_len > 0) { 20 | memset(ser + 4 + str_real_len, '\0', str_pad_len); 21 | } 22 | *(uint16_t *)(ser + 4 + str_len) = bbp_eint16(BBP_LITTLE, n16); 23 | 24 | bbp_print_hex("ser ", ser, sizeof(ser)); 25 | printf("ser (exp): %s\n", ser_exp); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /ex-hashes.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "hash.h" 3 | 4 | int main() { 5 | char message[] = "Hello Bitcoin!"; 6 | uint16_t prefix = 0xd17f; 7 | uint8_t suffix = 0x8c; 8 | uint8_t digest[32]; 9 | uint8_t ser[35]; 10 | 11 | const char sha256_exp[] = "518ad5a375fa52f84b2b3df7933ad685eb62cf69869a96731561f94d10826b5c"; 12 | const char hash256_exp[] = "90986ea4e28b847cc7f9beba87ea81b221ca6eaf9828a8b04c290c21d891bcda"; 13 | const char ser_exp[] = "7fd190986ea4e28b847cc7f9beba87ea81b221ca6eaf9828a8b04c290c21d891bcda8c"; 14 | 15 | /* */ 16 | 17 | /* SHA-2 digest is big-endian */ 18 | 19 | bbp_sha256(digest, (uint8_t *)message, strlen(message)); 20 | bbp_print_hex("SHA256(message) ", digest, 32); 21 | printf("SHA256(message) (exp): %s\n", sha256_exp); 22 | 23 | bbp_sha256(digest, digest, 32); 24 | bbp_print_hex("hash256(message) ", digest, 32); 25 | printf("hash256(message) (exp): %s\n", hash256_exp); 26 | 27 | *(uint16_t *)(ser) = bbp_eint16(BBP_LITTLE, prefix); 28 | memcpy(ser + 2, digest, 32); 29 | *(ser + 2 + 32) = suffix; 30 | 31 | bbp_print_hex("ser ", ser, sizeof(ser)); 32 | printf("ser (exp): %s\n", ser_exp); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /ex-integers.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | int main() { 4 | uint8_t n8 = 0x01; 5 | uint16_t n16 = 0x4523; 6 | uint32_t n32 = 0xcdab8967; 7 | uint64_t n64 = 0xdebc9a78563412ef; 8 | uint8_t ser[15]; 9 | 10 | const char ser_exp[] = "0123456789abcdef123456789abcde"; 11 | 12 | /* */ 13 | 14 | *ser = n8; 15 | *(uint16_t *)(ser + 1) = bbp_eint16(BBP_LITTLE, n16); 16 | *(uint32_t *)(ser + 3) = bbp_eint32(BBP_LITTLE, n32); 17 | *(uint64_t *)(ser + 7) = bbp_eint64(BBP_LITTLE, n64); 18 | 19 | bbp_print_hex("ser ", ser, sizeof(ser)); 20 | printf("ser (exp): %s\n", ser_exp); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ex-message.txt: -------------------------------------------------------------------------------- 1 | This is a very confidential message 2 | -------------------------------------------------------------------------------- /ex-signature.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keeshux/basic-blockchain-programming/b0d0266f09bca70fff6317446cd3f097cb15203d/ex-signature.der -------------------------------------------------------------------------------- /ex-tx-build.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "endian.h" 3 | #include "tx.h" 4 | #include "hash.h" 5 | #include "ec.h" 6 | 7 | int main() { 8 | bbp_txout_t outs[2]; 9 | bbp_txout_t prev_outs[1]; 10 | bbp_txin_t ins_sign[1]; 11 | bbp_outpoint_t outpoint; 12 | bbp_tx_t tx; 13 | uint8_t *msg; 14 | size_t msg_len; 15 | 16 | const char msg_exp[] = "0100000001f3a27f485f9833c8318c490403307fef1397121b5dd8fe70777236e7371c4ef3000000001976a9146bf19e55f94d986b4640c154d86469934191951188acffffffff02e0fe7e01000000001976a91418ba14b3682295cb05230e31fecb00089240660888ace084b003000000001976a9146bf19e55f94d986b4640c154d86469934191951188ac0000000001000000"; 17 | 18 | /* */ 19 | 20 | /* output 1 (0.251 BTC) */ 21 | bbp_txout_create_p2pkh(&outs[0], 25100000, "18ba14b3682295cb05230e31fecb000892406608"); 22 | 23 | /* output 2 (change, 0.619 BTC) */ 24 | bbp_txout_create_p2pkh(&outs[1], 61900000, "6bf19e55f94d986b4640c154d864699341919511"); 25 | 26 | /* input from utxo (0.87 BTC) */ 27 | bbp_outpoint_fill(&outpoint, "f34e1c37e736727770fed85d1b129713ef7f300304498c31c833985f487fa2f3", 0); 28 | bbp_txout_create_p2pkh(&prev_outs[0], 87000000, "6bf19e55f94d986b4640c154d864699341919511"); 29 | bbp_txin_create_signable(&ins_sign[0], &outpoint, &prev_outs[0]); 30 | 31 | /* message */ 32 | tx.version = bbp_eint32(BBP_LITTLE, 1); 33 | tx.outputs_len = 2; 34 | tx.outputs = outs; 35 | tx.inputs_len = 1; 36 | tx.inputs = ins_sign; 37 | tx.locktime = 0; 38 | msg_len = bbp_tx_size(&tx, BBP_SIGHASH_ALL); 39 | msg = malloc(msg_len); 40 | bbp_tx_serialize(&tx, msg, BBP_SIGHASH_ALL); 41 | 42 | /* */ 43 | 44 | bbp_print_hex("outs[0].script", outs[0].script, outs[0].script_len); 45 | bbp_print_hex("outs[1].script", outs[1].script, outs[1].script_len); 46 | puts(""); 47 | bbp_print_hex("ins_sign[0].outpoint.txid", ins_sign[0].outpoint.txid, 32); 48 | printf("ins_sign[0].outpoint.index: %u\n", ins_sign[0].outpoint.index); 49 | bbp_print_hex("ins_sign[0].script", ins_sign[0].script, ins_sign[0].script_len); 50 | puts(""); 51 | bbp_print_hex("msg ", msg, msg_len); 52 | printf("msg (exp): %s\n", msg_exp); 53 | 54 | free(msg); 55 | bbp_txout_destroy(&outs[0]); 56 | bbp_txout_destroy(&outs[1]); 57 | bbp_txout_destroy(&prev_outs[0]); 58 | bbp_txin_destroy(&ins_sign[0]); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /ex-tx-pack.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "endian.h" 3 | #include "tx.h" 4 | #include "hash.h" 5 | #include "ec.h" 6 | 7 | int main() { 8 | bbp_txin_t ins[1]; 9 | bbp_txout_t outs[2]; 10 | bbp_outpoint_t outpoint; 11 | bbp_tx_t tx; 12 | uint8_t *rawtx; 13 | size_t rawtx_len; 14 | uint8_t txid[32]; 15 | 16 | const char txid_exp[] = "9996e2f64b6af0232dd9c897395ce51fdd35e6359edd2855c60ff823d8d657d1"; 17 | 18 | /* */ 19 | 20 | /* inputs */ 21 | bbp_outpoint_fill(&outpoint, "f34e1c37e736727770fed85d1b129713ef7f300304498c31c833985f487fa2f3", 0); 22 | bbp_txin_create_p2pkh(&ins[0], &outpoint, "30440220111a482aba6afba12a6f27de767dd4d06417def665bd100bc68c42845c752a8f02205e86f5e054b2c6cac5d663664e35779fb034387c07848bc7724442cacf659324", "0282006e9398a6986eda61fe91674c3a108c399475bf1e738f19dfc2db11db1d28", BBP_SIGHASH_ALL); 23 | 24 | /* outputs */ 25 | bbp_txout_create_p2pkh(&outs[0], 25100000, "18ba14b3682295cb05230e31fecb000892406608"); 26 | bbp_txout_create_p2pkh(&outs[1], 61900000, "6bf19e55f94d986b4640c154d864699341919511"); 27 | 28 | /* packing */ 29 | tx.version = bbp_eint32(BBP_LITTLE, 1); 30 | tx.outputs_len = 2; 31 | tx.outputs = outs; 32 | tx.inputs_len = 1; 33 | tx.inputs = ins; 34 | tx.locktime = 0; 35 | rawtx_len = bbp_tx_size(&tx, 0); 36 | rawtx = malloc(rawtx_len); 37 | bbp_tx_serialize(&tx, rawtx, 0); 38 | 39 | /* txid (print big-endian) */ 40 | bbp_hash256(txid, rawtx, rawtx_len); 41 | bbp_reverse(txid, 32); 42 | 43 | /* */ 44 | 45 | bbp_print_hex("ins[0].script", ins[0].script, ins[0].script_len); 46 | bbp_print_hex("outs[0].script", outs[0].script, outs[0].script_len); 47 | bbp_print_hex("outs[1].script", outs[1].script, outs[1].script_len); 48 | puts(""); 49 | bbp_print_hex("rawtx", rawtx, rawtx_len); 50 | printf("size: %lu bytes\n", rawtx_len); 51 | puts(""); 52 | bbp_print_hex("txid ", txid, 32); 53 | printf("txid (exp): %s\n", txid_exp); 54 | 55 | free(rawtx); 56 | bbp_txin_destroy(&ins[0]); 57 | bbp_txout_destroy(&outs[0]); 58 | bbp_txout_destroy(&outs[1]); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /ex-tx-sign.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "endian.h" 3 | #include "tx.h" 4 | #include "hash.h" 5 | #include "ec.h" 6 | 7 | int main() { 8 | uint8_t priv[32]; 9 | EC_KEY *key; 10 | uint8_t *msg; 11 | size_t msg_len; 12 | uint8_t digest[32]; 13 | uint8_t *sig; 14 | unsigned int sig_len; 15 | 16 | /* */ 17 | 18 | /* keypair */ 19 | bbp_parse_hex(priv, "16260783e40b16731673622ac8a5b045fc3ea4af70f727f3f9e92bdd3a1ddc42"); 20 | key = bbp_ec_new_keypair(priv); 21 | 22 | /* message */ 23 | msg = bbp_alloc_hex("0100000001f3a27f485f9833c8318c490403307fef1397121b5dd8fe70777236e7371c4ef3000000001976a9146bf19e55f94d986b4640c154d86469934191951188acffffffff02e0fe7e01000000001976a91418ba14b3682295cb05230e31fecb00089240660888ace084b003000000001976a9146bf19e55f94d986b4640c154d86469934191951188ac0000000001000000", &msg_len); 24 | 25 | /* signature */ 26 | bbp_hash256(digest, msg, msg_len); 27 | sig_len = ECDSA_size(key); 28 | sig = malloc(sig_len); 29 | ECDSA_sign(0, digest, sizeof(digest), sig, &sig_len, key); 30 | 31 | /* */ 32 | 33 | bbp_print_hex("digest", digest, sizeof(digest)); 34 | bbp_print_hex("signature", sig, sig_len); 35 | 36 | free(sig); 37 | free(msg); 38 | EC_KEY_free(key); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /ex-vardata.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "varint.h" 3 | 4 | int main() { 5 | uint8_t bytes[] = { 6 | 0xfd, 0x0a, 0x00, 0xe3, 7 | 0x03, 0x41, 0x8b, 0xa6, 8 | 0x20, 0xe1, 0xb7, 0x83, 9 | 0x60 10 | }; 11 | 12 | size_t len; 13 | size_t varlen; 14 | uint8_t data[100] = { 0 }; 15 | 16 | const char data_exp[] = "e303418ba620e1b78360"; 17 | 18 | /* */ 19 | 20 | len = bbp_varint_get(bytes, &varlen); 21 | printf("len: %lu, varlen: %lu\n", len, varlen); 22 | 23 | memcpy(data, bytes + varlen, len); 24 | 25 | bbp_print_hex("data ", data, len); 26 | printf("data (exp): %s\n", data_exp); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /ex-varints.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "varint.h" 3 | 4 | typedef struct { 5 | uint16_t fixed1; 6 | uint64_t var2; 7 | uint32_t fixed3; 8 | uint8_t fixed4; 9 | } foo_t; 10 | 11 | int main() { 12 | uint8_t bytes[] = { 13 | 0x13, 0x9c, 0xfd, 0x7d, 14 | 0x80, 0x44, 0x6b, 0xa2, 15 | 0x20, 0xcc 16 | }; 17 | 18 | foo_t decoded; 19 | size_t varlen; 20 | 21 | const foo_t exp = { 22 | 0x9c13, 23 | 0x807d, 24 | 0x20a26b44, 25 | 0xcc 26 | }; 27 | 28 | /* */ 29 | 30 | decoded.fixed1 = bbp_eint16(BBP_LITTLE, *(uint16_t *)bytes); 31 | decoded.var2 = bbp_varint_get(bytes + 2, &varlen); 32 | decoded.fixed3 = bbp_eint32(BBP_LITTLE, *(uint32_t *)(bytes + 2 + varlen)); 33 | decoded.fixed4 = *(bytes + 2 + varlen + 4); 34 | 35 | printf("fixed1 : %x\n", decoded.fixed1); 36 | printf("fixed1 (exp): %x\n", exp.fixed1); 37 | printf("var2 : %llx\n", decoded.var2); 38 | printf("var2 (exp): %llx\n", exp.var2); 39 | printf("fixed3 : %x\n", decoded.fixed3); 40 | printf("fixed3 (exp): %x\n", exp.fixed3); 41 | printf("fixed4 : %x\n", decoded.fixed4); 42 | printf("fixed4 (exp): %x\n", exp.fixed4); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /ex-wif.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "base58.h" 3 | #include "hash.h" 4 | 5 | int main() { 6 | uint8_t priv_bytes[32] = { 7 | 0x16, 0x26, 0x07, 0x83, 0xe4, 0x0b, 0x16, 0x73, 8 | 0x16, 0x73, 0x62, 0x2a, 0xc8, 0xa5, 0xb0, 0x45, 9 | 0xfc, 0x3e, 0xa4, 0xaf, 0x70, 0xf7, 0x27, 0xf3, 10 | 0xf9, 0xe9, 0x2b, 0xdd, 0x3a, 0x1d, 0xdc, 0x42 11 | }; 12 | uint8_t wif_bytes[34]; 13 | char *wif; 14 | 15 | const char wif_exp[] = "cNKkmrwHuShs2mvkVEKfXULxXhxRo3yy1cK6sq62uBp2Pc8Lsa76"; 16 | 17 | /* */ 18 | 19 | bbp_print_hex("priv", priv_bytes, sizeof(priv_bytes)); 20 | 21 | wif_bytes[0] = 0xef; 22 | memcpy(wif_bytes + 1, priv_bytes, 32); 23 | wif_bytes[33] = 0x01; 24 | 25 | wif = bbp_base58check(wif_bytes, 34); 26 | printf("WIF : %s\n", wif); 27 | printf("WIF (exp): %s\n", wif_exp); 28 | free(wif); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H 2 | #define __HASH_H 3 | 4 | #include 5 | #include 6 | 7 | void bbp_sha256(uint8_t *digest, const uint8_t *message, size_t len) { 8 | SHA256_CTX ctx; 9 | SHA256_Init(&ctx); 10 | SHA256_Update(&ctx, message, len); 11 | SHA256_Final(digest, &ctx); 12 | } 13 | 14 | void bbp_rmd160(uint8_t *digest, const uint8_t *message, size_t len) { 15 | RIPEMD160_CTX ctx; 16 | RIPEMD160_Init(&ctx); 17 | RIPEMD160_Update(&ctx, message, len); 18 | RIPEMD160_Final(digest, &ctx); 19 | } 20 | 21 | void bbp_hash256(uint8_t *digest, const uint8_t *message, size_t len) { 22 | uint8_t tmp[SHA256_DIGEST_LENGTH]; 23 | bbp_sha256(tmp, message, len); 24 | bbp_sha256(digest, tmp, SHA256_DIGEST_LENGTH); 25 | } 26 | 27 | void bbp_hash160(uint8_t *digest, const uint8_t *message, size_t len) { 28 | uint8_t tmp[SHA256_DIGEST_LENGTH]; 29 | bbp_sha256(tmp, message, len); 30 | bbp_rmd160(digest, tmp, SHA256_DIGEST_LENGTH); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | OPENSSL_INCLUDE=/usr/local/opt/openssl/include/ 3 | touch $1.c 4 | gcc -ansi -Wall -Wno-deprecated-declarations -Wno-long-long -I $OPENSSL_INCLUDE -pedantic -lcrypto -o $1.out $1.c 5 | ./$1.out 6 | -------------------------------------------------------------------------------- /tx.h: -------------------------------------------------------------------------------- 1 | #ifndef __TX_H 2 | #define __TX_H 3 | 4 | #include 5 | #include "common.h" 6 | #include "endian.h" 7 | #include "varint.h" 8 | 9 | typedef struct { 10 | uint64_t value; 11 | uint64_t script_len; 12 | uint8_t *script; 13 | } bbp_txout_t; 14 | 15 | typedef struct { 16 | uint8_t txid[32]; 17 | uint32_t index; 18 | } bbp_outpoint_t; 19 | 20 | typedef struct { 21 | bbp_outpoint_t outpoint; 22 | uint64_t script_len; 23 | uint8_t *script; 24 | uint32_t sequence; 25 | } bbp_txin_t; 26 | 27 | typedef struct { 28 | uint32_t version; 29 | uint64_t inputs_len; 30 | bbp_txin_t *inputs; 31 | uint64_t outputs_len; 32 | bbp_txout_t *outputs; 33 | uint32_t locktime; 34 | } bbp_tx_t; 35 | 36 | typedef enum { 37 | BBP_SIGHASH_ALL = 0x01 38 | } bbp_sighash_t; 39 | 40 | typedef uint8_t *bbp_message_t; 41 | 42 | void bbp_outpoint_fill(bbp_outpoint_t *outpoint, const char *txid, uint32_t index) { 43 | bbp_parse_hex(outpoint->txid, txid); 44 | bbp_reverse(outpoint->txid, 32); 45 | outpoint->index = bbp_eint32(BBP_LITTLE, index); 46 | } 47 | 48 | void bbp_txout_create_p2pkh(bbp_txout_t *txout, const uint64_t value, const char *hash160) { 49 | char script[52] = { 0 }; 50 | sprintf(script, "76a914%s88ac", hash160); 51 | 52 | txout->value = bbp_eint64(BBP_LITTLE, value); 53 | txout->script = bbp_alloc_hex(script, (size_t *)&txout->script_len); 54 | } 55 | 56 | void bbp_txout_destroy(bbp_txout_t *txout) { 57 | free(txout->script); 58 | } 59 | 60 | void bbp_txin_create_p2pkh(bbp_txin_t *txin, const bbp_outpoint_t *outpoint, 61 | const char *sig, const char *pub, bbp_sighash_t flag) { 62 | 63 | char script[400] = { 0 }; 64 | sprintf(script, "%02lx%s%02x%02lx%s", strlen(sig) / 2 + 1, sig, flag, strlen(pub) / 2, pub); 65 | 66 | memcpy(&txin->outpoint, outpoint, sizeof(bbp_outpoint_t)); 67 | txin->script = bbp_alloc_hex(script, (size_t *)&txin->script_len); 68 | txin->sequence = 0xffffffff; 69 | } 70 | 71 | void bbp_txin_destroy(bbp_txin_t *txin) { 72 | free(txin->script); 73 | } 74 | 75 | /* signable message */ 76 | 77 | void bbp_txin_create_signable(bbp_txin_t *txin, const bbp_outpoint_t *outpoint, const bbp_txout_t *utxo) { 78 | memcpy(&txin->outpoint, outpoint, sizeof(bbp_outpoint_t)); 79 | txin->script_len = utxo->script_len; 80 | txin->script = malloc(utxo->script_len); 81 | memcpy(txin->script, utxo->script, utxo->script_len); 82 | txin->sequence = 0xffffffff; 83 | } 84 | 85 | void bbp_txin_create_truncated(bbp_txin_t *txin, const bbp_outpoint_t *outpoint) { 86 | memcpy(&txin->outpoint, outpoint, sizeof(bbp_outpoint_t)); 87 | txin->script_len = 0; 88 | txin->script = NULL; 89 | txin->sequence = 0xffffffff; 90 | } 91 | 92 | size_t bbp_tx_size(const bbp_tx_t *tx, bbp_sighash_t flag) { 93 | size_t size = 0; 94 | int i; 95 | 96 | /* version */ 97 | size += sizeof(uint32_t); 98 | 99 | /* inputs count */ 100 | size += bbp_varint_size(tx->inputs_len); 101 | 102 | /* inputs */ 103 | for (i = 0; i < tx->inputs_len; ++i) { 104 | bbp_txin_t *txin = &tx->inputs[i]; 105 | 106 | /* outpoint */ 107 | size += sizeof(bbp_outpoint_t); 108 | 109 | /* script */ 110 | size += bbp_varint_size(txin->script_len); 111 | size += txin->script_len; 112 | 113 | /* sequence */ 114 | size += sizeof(uint32_t); 115 | } 116 | 117 | /* outputs count */ 118 | size += bbp_varint_size(tx->outputs_len); 119 | 120 | /* outputs */ 121 | for (i = 0; i < tx->outputs_len; ++i) { 122 | bbp_txout_t *txout = &tx->outputs[i]; 123 | 124 | /* value */ 125 | size += sizeof(uint64_t); 126 | 127 | /* script */ 128 | size += bbp_varint_size(txout->script_len); 129 | size += txout->script_len; 130 | } 131 | 132 | /* locktime */ 133 | size += sizeof(uint32_t); 134 | 135 | if (flag) { 136 | 137 | /* sighash */ 138 | size += sizeof(uint32_t); 139 | } 140 | 141 | return size; 142 | } 143 | 144 | void bbp_tx_serialize(const bbp_tx_t *tx, uint8_t *raw, bbp_sighash_t flag) { 145 | uint8_t *ptr; 146 | size_t varlen; 147 | int i; 148 | 149 | ptr = raw; 150 | 151 | /* version */ 152 | *(uint32_t *)ptr = bbp_eint32(BBP_LITTLE, tx->version); 153 | ptr += sizeof(uint32_t); 154 | 155 | /* inputs count */ 156 | bbp_varint_set(ptr, tx->inputs_len, &varlen); 157 | ptr += varlen; 158 | 159 | /* inputs */ 160 | for (i = 0; i < tx->inputs_len; ++i) { 161 | bbp_txin_t *txin = &tx->inputs[i]; 162 | 163 | /* outpoint */ 164 | memcpy(ptr, txin->outpoint.txid, 32); 165 | ptr += 32; 166 | *(uint32_t *)ptr = bbp_eint32(BBP_LITTLE, txin->outpoint.index); 167 | ptr += sizeof(uint32_t); 168 | 169 | /* script */ 170 | bbp_varint_set(ptr, txin->script_len, &varlen); 171 | ptr += varlen; 172 | memcpy(ptr, txin->script, txin->script_len); 173 | ptr += txin->script_len; 174 | 175 | /* sequence */ 176 | *(uint32_t *)ptr = bbp_eint32(BBP_LITTLE, txin->sequence); 177 | ptr += sizeof(uint32_t); 178 | } 179 | 180 | /* outputs count */ 181 | bbp_varint_set(ptr, tx->outputs_len, &varlen); 182 | ptr += varlen; 183 | 184 | /* outputs */ 185 | for (i = 0; i < tx->outputs_len; ++i) { 186 | bbp_txout_t *txout = &tx->outputs[i]; 187 | 188 | /* value */ 189 | *(uint64_t *)ptr = bbp_eint64(BBP_LITTLE, txout->value); 190 | ptr += sizeof(uint64_t); 191 | 192 | /* script */ 193 | bbp_varint_set(ptr, txout->script_len, &varlen); 194 | ptr += varlen; 195 | memcpy(ptr, txout->script, txout->script_len); 196 | ptr += txout->script_len; 197 | } 198 | 199 | /* locktime */ 200 | *(uint32_t *)ptr = bbp_eint32(BBP_LITTLE, tx->locktime); 201 | ptr += sizeof(uint32_t); 202 | 203 | if (flag) { 204 | 205 | /* sighash */ 206 | *(uint32_t *)ptr = bbp_eint32(BBP_LITTLE, flag); 207 | } 208 | } 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /varint.h: -------------------------------------------------------------------------------- 1 | #ifndef __VARINT_H 2 | #define __VARINT_H 3 | 4 | #include 5 | #include "endian.h" 6 | 7 | typedef enum { 8 | BBP_VARINT16 = 0xfd, 9 | BBP_VARINT32 = 0xfe, 10 | BBP_VARINT64 = 0xff 11 | } bbp_varint_t; 12 | 13 | uint64_t bbp_varint_get(uint8_t *bytes, size_t *len) { 14 | uint8_t prefix = *bytes; 15 | uint64_t value; 16 | 17 | *len = sizeof(uint8_t); 18 | 19 | if (prefix < BBP_VARINT16) { 20 | value = prefix; 21 | } else { 22 | uint8_t *ptr = bytes + *len; 23 | 24 | switch (prefix) { 25 | case BBP_VARINT16: 26 | value = bbp_eint16(BBP_LITTLE, *(uint16_t *)ptr); 27 | *len += sizeof(uint16_t); 28 | break; 29 | case BBP_VARINT32: 30 | value = bbp_eint32(BBP_LITTLE, *(uint32_t *)ptr); 31 | *len += sizeof(uint32_t); 32 | break; 33 | case BBP_VARINT64: 34 | value = bbp_eint64(BBP_LITTLE, *(uint64_t *)ptr); 35 | *len += sizeof(uint64_t); 36 | break; 37 | } 38 | } 39 | 40 | return value; 41 | } 42 | 43 | void bbp_varint_set(uint8_t *bytes, uint64_t n, size_t *len) { 44 | *len = sizeof(uint8_t); 45 | 46 | if (n < BBP_VARINT16) { 47 | *bytes = (uint8_t)n; 48 | } else { 49 | uint8_t header; 50 | 51 | if (n <= UINT16_MAX) { 52 | header = BBP_VARINT16; 53 | *(uint16_t *)(bytes + 1) = bbp_eint16(BBP_LITTLE, n); 54 | *len += sizeof(uint16_t); 55 | } else if (n <= UINT32_MAX) { 56 | header = BBP_VARINT32; 57 | *(uint32_t *)(bytes + 1) = bbp_eint32(BBP_LITTLE, n); 58 | *len += sizeof(uint32_t); 59 | } else { 60 | header = BBP_VARINT64; 61 | *(uint64_t *)(bytes + 1) = bbp_eint64(BBP_LITTLE, n); 62 | *len += sizeof(uint64_t); 63 | } 64 | 65 | *bytes = header; 66 | } 67 | } 68 | 69 | size_t bbp_varint_size(uint64_t n) { 70 | if (n < BBP_VARINT16) { 71 | return 1; 72 | } else if (n <= UINT16_MAX) { 73 | return 1 + sizeof(uint16_t); 74 | } else if (n <= UINT32_MAX) { 75 | return 1 + sizeof(uint32_t); 76 | } else { 77 | return 1 + sizeof(uint64_t); 78 | } 79 | } 80 | 81 | #endif 82 | --------------------------------------------------------------------------------