现在的位置: 首页 > 综合 > 正文

【比特币】脑钱包

2019年05月15日 ⁄ 综合 ⁄ 共 15302字 ⁄ 字号 评论关闭

代码参考 

https://github.com/openssl/openssl/blob/master/crypto/ec/ec_key.c

https://github.com/openssl/openssl/blob/master/apps/ecparam.c

查看手册:man --manpath=/d/local/ssl/man OBJ_sn2nid

基本步骤

1) 创建EC_KEY结构体

EC_KEY *EC_KEY_new(void)
	{
	EC_KEY *ret;

	ret=(EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY));
	if (ret == NULL)
		{
		ECerr(EC_F_EC_KEY_NEW, ERR_R_MALLOC_FAILURE);
		return(NULL);
		}

	ret->version = 1;	
	ret->flags = 0;
	ret->group   = NULL;
	ret->pub_key = NULL;
	ret->priv_key= NULL;
	ret->enc_flag= 0; 
	ret->conv_form = POINT_CONVERSION_UNCOMPRESSED;
	ret->references= 1;
	ret->method_data = NULL;
	return(ret);
	}

以上创建的EC_KEY的group成员是空的,需要调用

EC_KEY_set_group(eckey,group)

来设置group参数。


从曲线名称可以得到group参数结构

		int nid = OBJ_sn2nid(curve_name);
		int nid = EC_curve_nist2nid(curve_name);
		EC_GROUP * group = EC_GROUP_new_by_curve_name(nid);


也可以直接从curve_name创建EC_KEY结构体并设置EC_GROUP成员

EC_KEY *EC_KEY_new_by_curve_name(int nid)
	{
	EC_KEY *ret = EC_KEY_new();
	if (ret == NULL)
		return NULL;
	ret->group = EC_GROUP_new_by_curve_name(nid);
	if (ret->group == NULL)
		{
		EC_KEY_free(ret);
		return NULL;
		}
	return ret;
	}

2) 销毁结构体

void EC_KEY_free(EC_KEY *r)
	{
	int i;

	if (r == NULL) return;

	i=CRYPTO_add(&r->references,-1,CRYPTO_LOCK_EC);
#ifdef REF_PRINT
	REF_PRINT("EC_KEY",r);
#endif
	if (i > 0) return;
#ifdef REF_CHECK
	if (i < 0)
		{
		fprintf(stderr,"EC_KEY_free, bad reference count\n");
		abort();
		}
#endif

	if (r->group    != NULL) 
		EC_GROUP_free(r->group);
	if (r->pub_key  != NULL)
		EC_POINT_free(r->pub_key);
	if (r->priv_key != NULL)
		BN_clear_free(r->priv_key);

	EC_EX_DATA_free_all_data(&r->method_data);

	OPENSSL_cleanse((void *)r, sizeof(EC_KEY));

	OPENSSL_free(r);
	}

3) 生成EC_KEY的私钥和公钥

int EC_KEY_generate_key(EC_KEY *eckey)
	{	
	int	ok = 0;
	BN_CTX	*ctx = NULL;
	BIGNUM	*priv_key = NULL, *order = NULL;
	EC_POINT *pub_key = NULL;

#ifdef OPENSSL_FIPS
	if(FIPS_selftest_failed())
		{
		FIPSerr(FIPS_F_EC_KEY_GENERATE_KEY,FIPS_R_FIPS_SELFTEST_FAILED);
		return 0;
		}
#endif

	if (!eckey || !eckey->group)
		{
		ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
		return 0;
		}

	if ((order = BN_new()) == NULL) goto err;
	if ((ctx = BN_CTX_new()) == NULL) goto err;

	if (eckey->priv_key == NULL)
		{
		priv_key = BN_new();
		if (priv_key == NULL)
			goto err;
		}
	else
		priv_key = eckey->priv_key;

	if (!EC_GROUP_get_order(eckey->group, order, ctx))
		goto err;

#ifdef OPENSSL_FIPS
	if (!fips_check_ec_prng(eckey))
		goto err;
#endif

	do // 开始随机化私钥数据,脑钱包可以在这里设置随机数据(256bits的Hash)
		if (!BN_rand_range(priv_key, order))
			goto err;
	while (BN_is_zero(priv_key));

	if (eckey->pub_key == NULL)
		{
		pub_key = EC_POINT_new(eckey->group);
		if (pub_key == NULL)
			goto err;
		}
	else
		pub_key = eckey->pub_key;

	if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx))
		goto err;

	eckey->priv_key = priv_key;
	eckey->pub_key  = pub_key;

#ifdef OPENSSL_FIPS
	if(!fips_check_ec(eckey))
		{
		eckey->priv_key = NULL;
		eckey->pub_key  = NULL;
	    	goto err;
		}
#endif

	ok=1;

err:	
	if (order)
		BN_free(order);
	if (pub_key  != NULL && eckey->pub_key  == NULL)
		EC_POINT_free(pub_key);
	if (priv_key != NULL && eckey->priv_key == NULL)
		BN_free(priv_key);
	if (ctx != NULL)
		BN_CTX_free(ctx);
	return(ok);
	}

4) 如何使用自定义的私钥数据

int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key)
	{
	if (key->priv_key)
		BN_clear_free(key->priv_key);
	key->priv_key = BN_dup(priv_key);
	return (key->priv_key == NULL) ? 0 : 1;
	}

但是设置新的私钥数据并不会导致EC_KEY_generate_key去计算新的公钥。

所以比特币的代码里面加入了EC_KEY_regenerate_key()这个实现。

openssl始终是使用BN_rand_range(,,,)来设置私钥数据。

5) 打印结果

EC_KEY_print_fp(FILE * stdout, EC_KEY * eckey, int offset);

使用openssl官方例子生成私钥的方式(随机私钥)

#include <openssl/opensslconf.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/objects.h>

int main(int argc, char * argv[])
{
	int nid;
	EC_KEY * eckey ;//= NULL;
	eckey = EC_KEY_new();
	nid = OBJ_sn2nid("secp256k1");
	EC_GROUP * group = EC_GROUP_new_by_curve_name(nid);
	EC_KEY_set_group(eckey, group);
	EC_KEY_generate_key(eckey);
        EC_KEY_print_fp(stdout, eckey, 0);
	EC_KEY_free(eckey);
	return 0;
}

编译:

g++ -DMONOLITH -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DOPENSSL_EC_BIN_PT_COMP -Wa,--noexecstack -DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall -DOPENSSL_BN_ASM_PART_WORDS -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DRMD160_ASM -DAES_ASM -DVPAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM   -I/d/local/include -L/d/local/lib -O0 -g brainwallet.c -o brainwallet -lcrypto -ldl

测试:

localhost ~ # ./brainwallet 
Private-Key: (256 bit)
priv:
    00:d5:28:8d:89:65:ba:29:5b:e3:75:68:de:3f:db:
    a2:17:16:d7:ed:ca:ce:06:63:7f:0e:c9:bc:94:b4:
    a6:04:e3
pub: 
    04:9b:01:ab:2d:da:2e:9e:47:90:89:7a:ba:59:d2:
    52:19:de:8d:51:a2:51:74:db:44:c0:8c:a2:ab:36:
    81:6c:5c:cf:c5:71:c9:e2:e4:fd:dd:78:50:e1:0e:
    c9:85:49:84:a3:1f:cf:4c:f1:e5:0a:ad:bf:0e:4b:
    0a:b7:85:67:9d
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
    ff:fc:2f
A:    0
B:    7 (0x7)
Generator (uncompressed):
    04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
    0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
    f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
    0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
    8f:fb:10:d4:b8
Order: 
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
    36:41:41
Cofactor:  1 (0x1)

Secp256k1

This is a graph of secp256k1's elliptic curve y2 = x3 + 7 over the real numbers. Note that because secp256k1 is actually defined over the field Zp, its
graph will in reality look like random scattered points, not anything like this.

secp256k1 refers to the parameters of the ECDSA curve used in
Bitcoin, and is defined in Standards for Efficient Cryptography (SEC) (Certicom Research, http://www.secg.org/collateral/sec2_final.pdf).

secp256k1 was almost never used before Bitcoin became popular, but it is now gaining in popularity due to its several nice properties. Most commonly-used curves have a random structure, but secp256k1 was constructed in a special non-random way which allows
for especially efficient computation. As a result, it is often more than 30% faster than other curves if the implementation is sufficiently optimized. Also, unlike the popular NIST curves, secp256k1's constants were selected in a predictable way, which significantly
reduces the possibility that the curve's creator inserted any sort of backdoor into the curve.

Technical details

As excerpted from Standards:

The elliptic curve domain parameters over Fp associated with a Koblitz curve secp256k1 are specified by the sextuple T = (p,a,b,G,n,h) where the finite field Fp is
defined by:

  • p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F
  • = 2256 - 232 - 29 - 28 - 27 - 26 -
    24 - 1

The curve Ey2 = x3+ax+b over Fp is defined by:

  • a = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
  • b = 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000007

The base point G in compressed form is:

  • G = 0279BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798

and in uncompressed form is:

  • G = 0479BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798483ADA77
    26A3C465 5DA4FBFC 0E1108A8 FD17B448 A6855419 9C47D08F FB10D4B8

Finally the order n of G and the cofactor are:

  • n = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
  • h = 01

从上面这些参数可以看出,官方oepnssl ecparam -genkey的实现,

使用BN_rand_range(privkey, maxrange=FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141)。

比特币官方代码的实现方式

1) 从随机数数组设置私钥

void SetSecretBytes(const unsigned char vch[32]) { // 设置32字节的数组到大整数(256b)
	bool ret;
	BIGNUM bn;
	BN_init(&bn);
	ret = BN_bin2bn(vch, 32, &bn);
	assert(ret);
	ret = EC_KEY_regenerate_key(pkey, &bn);// 生成私钥和公钥
	assert(ret);
	BN_clear_free(&bn);
}

2) 从随机数生成公钥和私钥

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey); // 获取ec计算群

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group); // (x,y)坐标

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) // 公钥=私钥×基点
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

3) 修改后的例子用测试数据重新生成

#include <openssl/opensslconf.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/bn.h>
#include <assert.h>

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey); // 获取ec计算群

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group); // (x,y)坐标

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) // 公钥=私钥×基点
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

// 从32字节数组重新设置EC_KEY结构
void SetSecretBytes(EC_KEY * pkey, const unsigned char vch[32]) { // 设置32字节的数组到大整数(256b)
	bool ret;
	BIGNUM bn;
	BN_init(&bn);
	ret = BN_bin2bn(vch, 32, &bn);
	assert(ret);
	ret = EC_KEY_regenerate_key(pkey, &bn);// 生成私钥和公钥
	assert(ret);
	BN_clear_free(&bn);
}

int main(int argc, char * argv[])
{
	unsigned char vch[32];
	int nid;
	EC_KEY * eckey ;//= NULL;
	eckey = EC_KEY_new();
	nid = OBJ_sn2nid("secp256k1");
	EC_GROUP * group = EC_GROUP_new_by_curve_name(nid);
	EC_KEY_set_group(eckey, group);
	
	// 官方的随机数方式生成EC_KEY
	EC_KEY_generate_key(eckey);
	// 打印结果
	EC_KEY_print_fp(stdout, eckey, 0);
	
	// 设置随机数
	memset(vch, 0xa0, sizeof(vch));
	// 重新计算
	SetSecretBytes(eckey, vch);
	// 打印结果
	EC_KEY_print_fp(stdout, eckey, 0);
	
	EC_KEY_free(eckey);
	return 0;
}

localhost ~ # ./brainwallet 
Private-Key: (256 bit)
priv://随机数组成的私钥
    00:e6:86:5e:09:25:b6:48:e8:50:7b:25:91:2b:cf:
    9d:6f:82:61:f1:3e:b9:12:d6:74:87:c4:39:77:b1:
    cc:c8:c1
pub: 
    04:54:f4:b6:19:e3:c6:74:d4:ec:ae:b0:e2:df:10:
    95:b2:03:48:59:0b:ff:c6:41:1c:ec:da:d6:9b:5f:
    81:32:cb:3d:06:6d:5f:15:a4:cb:a5:97:1b:d2:5c:
    ec:0f:7e:2b:a6:b7:c0:57:91:62:87:b2:b9:bd:6a:
    35:f4:f2:e8:9f
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
    ff:fc:2f
A:    0
B:    7 (0x7)
Generator (uncompressed):
    04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
    0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
    f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
    0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
    8f:fb:10:d4:b8
Order: 
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
    36:41:41
Cofactor:  1 (0x1)
Private-Key: (256 bit)
priv://用户设置的私钥
    00:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:
    a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:a0:
    a0:a0:a0
pub: 
    04:d5:4c:d3:79:30:b0:c5:58:73:33:d5:5b:f4:84:
    18:43:a9:22:a5:af:75:46:81:8b:a8:ac:2c:5c:fa:
    2c:f9:3d:c8:a9:86:2d:8d:b5:97:49:44:b7:cf:ea:
    53:03:92:80:ab:b7:cd:26:dd:f4:a5:28:b4:67:4b:
    68:d0:73:e0:57
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
    ff:fc:2f
A:    0
B:    7 (0x7)
Generator (uncompressed):
    04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
    0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
    f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
    0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
    8f:fb:10:d4:b8
Order: 
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
    36:41:41
Cofactor:  1 (0x1)

那么,脑钱包的雏形基本上就出来的。对任意数据做一次sha256sum得到256bit的hash值,用这个值作为vch的值,重新计算机可以到相应的公钥。

4)从用户命令行指定的hash值生成

#include <openssl/opensslconf.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/objects.h>
#include <openssl/bn.h>
#include <assert.h>
#include <string>
#include <vector>

const signed char p_util_hexdigit[256] =
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };

signed char HexDigit(char c)
{
    return p_util_hexdigit[(unsigned char)c];
}

std::vector<unsigned char> ParseHex(const char* psz)
{
    // convert hex dump to vector
    std::vector<unsigned char> vch;
    while (true)
    {
        while (isspace(*psz))
            psz++;
        signed char c = HexDigit(*psz++);
        if (c == (signed char)-1)
            break;
        unsigned char n = (c << 4);
        c = HexDigit(*psz++);
        if (c == (signed char)-1)
            break;
        n |= c;
        vch.push_back(n);
    }
    return vch;
}

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey); // 获取ec计算群

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group); // (x,y)坐标

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) // 公钥=私钥×基点
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

// 从32字节数组重新设置EC_KEY结构
void SetSecretBytes(EC_KEY * pkey, const std::string & sHexString) { // 十六进制字符串数组
	bool ret;
	BIGNUM * bn = NULL;
	ret = BN_hex2bn(&bn, sHexString.c_str());// 大端形式的16进制数组转换成bigNumber来运算
	                                         // 如果长度超多64字节(256bit),那么计算结果是错误的;
                                                 // 整数溢出了,但是openssl不会检测这个错误。
	assert(ret);
	ret = EC_KEY_regenerate_key(pkey, bn);// 生成私钥和公钥
	assert(ret);
	BN_clear_free(bn);
	bn = NULL;
}

int main(int argc, char * argv[])
{
	int nid;
	EC_KEY * eckey;
	
	eckey = EC_KEY_new();
	nid = OBJ_sn2nid("secp256k1");
	EC_GROUP * group = EC_GROUP_new_by_curve_name(nid);
	EC_KEY_set_group(eckey, group);
	
	// 官方的随机数方式生成EC_KEY
	EC_KEY_generate_key(eckey);	
	// 重新计算
	SetSecretBytes(eckey, argv[1]);
	// 打印结果
	EC_KEY_print_fp(stdout, eckey, 0);
	
	EC_KEY_free(eckey);
	return 0;
}

5) 测试结果:

localhost ~ # ./brainwallet aaaabbbbccccdddd0000111122223333aaaabbbbccccdddd0000111122223333
Private-Key: (256 bit)
priv:
    00:aa:aa:bb:bb:cc:cc:dd:dd:00:00:11:11:22:22:
    33:33:aa:aa:bb:bb:cc:cc:dd:dd:00:00:11:11:22:
    22:33:33
pub: 
    04:18:13:fc:6a:a4:2f:e3:b0:f1:82:d1:c8:b3:29:
    68:81:b3:c9:ad:b7:ac:eb:88:d1:ff:10:1d:d7:bc:
    d3:48:a0:93:b3:d1:8f:7c:4e:d1:8d:0b:61:1a:35:
    1d:3e:cf:70:aa:a0:7b:87:67:4f:1b:34:fe:6a:bd:
    a8:e8:48:24:d4
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
    ff:fc:2f
A:    0
B:    7 (0x7)
Generator (uncompressed):
    04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
    0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
    f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
    0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
    8f:fb:10:d4:b8
Order: 
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
    36:41:41
Cofactor:  1 (0x1)

6) 命令行举例

常规做法可能是执行./brainwallet $(sha256sum myphoto | sed -e "s/\([^ ]*\)[ ]*.*/\1/g")

localhost ~ # ./brainwallet $(sha256sum testfile | sed -e "s/\([^ ]*\)[ ]*.*/\1/g")
Private-Key: (256 bit)
priv:
    2c:f2:4d:ba:5f:b0:a3:0e:26:e8:3b:2a:c5:b9:e2:
    9e:1b:16:1e:5c:1f:a7:42:5e:73:04:33:62:93:8b:
    98:24
pub: 
    04:87:d8:20:42:d9:34:47:00:8d:fe:2a:f7:62:06:
    8a:1e:53:ff:39:4a:5b:f8:f6:8a:04:5f:a6:42:b9:
    9e:a5:d1:53:f5:77:dd:2d:ba:6c:7a:e4:cf:d7:b6:
    62:24:09:d7:ed:d2:d7:6d:d1:3a:80:92:cd:3a:f9:
    7b:77:bd:2c:77
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff:
    ff:fc:2f
A:    0
B:    7 (0x7)
Generator (uncompressed):
    04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
    0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
    f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
    0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
    8f:fb:10:d4:b8
Order: 
    00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
    36:41:41
Cofactor:  1 (0x1)
localhost ~ # echo -n $(sha256sum testfile | sed -e "s/\([^ ]*\)[ ]*.*/\1/g")
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

localhost ~ # cat testfile 
hello

7) 对比和提示

和js语言的在线版本对比(算法是一次SHA256)

得到你的比特币收款地址

脑钱包的原理大致如此,但是各个脑钱包工具的生成算法可能各异的,比如有的是2此的sha256sum,有的是3次,有的是pad了一些数据。所以,这些工具不一定兼容,也可能导致的你的脑钱包丢失,如果在试图使用多个脑钱包,而不知道他的算法的话。

抱歉!评论已关闭.