从ECDSA公钥生成比特币地址

bzzcjhmw  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(115)

我正在用C++编写简单的代码,使用OpenSSL来生成有效的比特币地址-私钥对。
我使用这个片段从给定的十六进制形式的私钥生成公钥:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>

int main()
{
     EC_KEY *eckey = NULL;
     EC_POINT *pub_key = NULL;
     const EC_GROUP *group = NULL;
     BIGNUM start;
     BIGNUM *res;
     BN_CTX *ctx;


     BN_init(&start);
     ctx = BN_CTX_new(); // ctx is an optional buffer to save time from allocating and deallocating memory whenever required

     res = &start;
     BN_hex2bn(&res,"30caae2fcb7c34ecadfddc45e0a27e9103bd7cfc87730d7818cc096b1266a683");
     eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
     group = EC_KEY_get0_group(eckey);
     pub_key = EC_POINT_new(group);

     EC_KEY_set_private_key(eckey, res);

     /* pub_key is a new uninitialized `EC_POINT*`.  priv_key res is a `BIGNUM*`. */
     if (!EC_POINT_mul(group, pub_key, res, NULL, NULL, ctx))
       printf("Error at EC_POINT_mul.\n");

     EC_KEY_set_public_key(eckey, pub_key);

     char *cc = EC_POINT_point2hex(group, pub_key, 4, ctx);

     char *c=cc;

     int i;

     for (i=0; i<130; i++) // 1 byte 0x42, 32 bytes for X coordinate, 32 bytes for Y coordinate
     {
       printf("%c", *c++);
     }

     printf("\n");

     BN_CTX_free(ctx);

     free(cc);

     return 0;
}

字符串
我想要的是将这个公钥转换为比特币地址-最快的方法是什么?我不知道如何从OpenSSL的BIGNUM创建RIPEMD 160。或许还有其他更好的解决方案?

s4chpxco

s4chpxco1#

假设你正在做的是基于这个转换:


的数据
我将描述你可以在伪代码中做些什么:
首先从公钥中提取x,y。

// get x and y from Public key "point"
EC_POINT_get_affine_coordinates_GFp(group, pub_key, x, y, ctx);
// convert BIGNUMs x, y into binary form
BN_bn2bin(x,x_char);
BN_bn2bin(y,y_char);

字符串
接下来,您需要多次执行消息摘要,包括3次sha256和1次ripemd160。在下面的伪代码中,我将向您展示如何执行ripemd160。要使用EVP_MD执行sha256,只需将EVP_ripemd160()替换为EVP_sha256(),并使用单个或多个EVP_DigestUpdate()更新(输入到EVP_MD)您的输入消息。

EVP_MD_CTX ctx;
EVP_MD_CTX_init(&md_ctx);
EVP_DigestInit(&md_ctx, EVP_ripemd160());
// hdr = 0x04
EVP_DigestUpdate(&md_ctx,hdr,1);
EVP_DigestUpdate(&md_ctx,x_char,32);
EVP_DigestUpdate(&md_ctx,y_char,32);
// put message degest into dgst and set length to dgstlen
EVP_DigestFinal(&md_ctx,dgst,&dgstlen); 
EVP_MD_CTX_cleanup(&md_ctx);


或者更简单的方法,直接调用sha256()ripemd160()。但是在调用哈希函数sha256()ripemd160()之前,需要准备好输入消息。
25字节二进制地址是ripemd160的结果,加上32字节校验和的前4个字节。您需要找到一种方法将其从Base 256转换为Base 58。我不认为OpenSSL支持这个。

rbl8hiat

rbl8hiat2#

25字节二进制地址是ripemd160的结果,加上32字节校验和的前4个字节。您需要找到一种方法将其从Base 256转换为Base 58。我不认为OpenSSL支持这个。https://drive.google.com/file/d/1bL52hFkZg9L2jIPdhEKw35ooFK78w1qm/view?usp=sharing

dba5bblo

dba5bblo3#

好了,重写了一些步骤,从上面的代码片段中生成私钥

#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <string.h>
#include <stdio.h>

const char* to_base58(const uint8_t* data, size_t size) {
    static char base58chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    BN_CTX* ctx = BN_CTX_new();
    BIGNUM num, div, rem, B58;
    BN_init(&num);
    BN_init(&div);
    BN_init(&rem);
    BN_init(&B58);
    BN_bin2bn(data, size, &num);
    BN_set_word(&B58, 58);
    char* result = (char*)malloc(100);
    memset(result, 0, 100);
    int index = 99;
    while (BN_cmp(&num, BN_value_one()) > 0) {
        BN_div(&div, &rem, &num, &B58, ctx);
        BN_copy(&num, &div);
        uint64_t r = BN_get_word(&rem);
        result[--index] = base58chars[r];
    }
    result[--index] = base58chars[BN_get_word(&num)];
    BN_CTX_free(ctx);
    return result + index;
}

void print_hex(uint8_t* data, size_t size) {
    for (size_t i = 0; i < size; i++) {
        printf("%02x", data[i]);
    }
    printf("\n");
}

int main() {
    uint8_t pubKey[65];
    size_t pubKeyLen = 65;
    EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1);
    BIGNUM* privKey = BN_new();
    BN_hex2bn(&privKey, "30caae2fcb7c34ecadfddc45e0a27e9103bd7cfc87730d7818cc096b1266a683");
    EC_KEY_set_private_key(key, privKey);
    EC_KEY_generate_key(key);
    EC_KEY_check_key(key);
    EC_POINT_point2oct(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, pubKey, pubKeyLen, NULL);
    uint8_t hash[SHA256_DIGEST_LENGTH];
    SHA256(pubKey, sizeof(pubKey), hash);
    uint8_t ripeHash[RIPEMD160_DIGEST_LENGTH];
    RIPEMD160(hash, sizeof(hash), ripeHash);
    uint8_t extendedRipe[1 + RIPEMD160_DIGEST_LENGTH + 4];
    extendedRipe[0] = 0x00;
    memcpy(extendedRipe + 1, ripeHash, sizeof(ripeHash));
    SHA256(extendedRipe, sizeof(ripeHash) + 1, hash);
    SHA256(hash, sizeof(hash), hash);
    memcpy(extendedRipe + 21, hash, 4);
    printf("Bitcoin address: %s\n", to_base58(extendedRipe, sizeof(extendedRipe)));
    return 0;
}

字符串

相关问题