区块链技术发展极为快速,以太坊账户体系是基于椭圆曲线的,这十分令人好奇,它是如何完成从私钥到地址的一系列操作的,让我们去探究一番。
椭圆曲线体系基础
以太坊的账户规则采用了椭圆曲线体系,椭圆曲线体系是密码学的重要组成部分,以太坊使用的是著名曲线,从本质上讲,以太坊账户是一个椭圆曲线数字签名算法私钥,2015年后,该技术在以太坊系统中广泛应用,只要掌握私钥,比如个人开发者小李掌握某个私钥后,就能对交易签名,进而完全掌控账户。
私钥与公钥关系
EC的私钥其实是一定范围内的随机数,这个随机数有最大数值范围。公钥是椭圆曲线里和私钥对应的点。两者关系用公式表示为某个私钥乘以G,G是椭圆曲线基点,这里的运算是非普通乘法运算。实际上很多开发者不用自己计算,因为库已提供完整计算功能,像赵工程师就直接用库完成相关任务。
地址生成步骤
// NewKeccak256 creates a new Keccak-256 hash.
func NewKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} }
// New256 creates a new SHA3-256 hash.
// Its generic security strength is 256 bits against preimage attacks,
// and 128 bits against collision attacks.
func New256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x06} }
从私钥到地址需经过三步,第一步是生成公钥,第二步是生成Hash,第三步是裁剪Hash。以太坊依靠算法生成Hash,所产生的Hash有32字节,然而以太坊地址仅取后20字节。2015年,此算法出现新变化,它朝着成为新的标准又前进了一步,如同众多新规则形成时那样,逐渐走向规范。
// Pad with this instance's domain-separator bits. We know that there's
// at least one byte of space in d.buf because, if it were full,
// permute would have been called to empty it. dsbyte also contains the
// first one bit for the padding. See the comment in the state struct.
d.buf = append(d.buf, dsbyte)
Hash算法情况
以太坊的源代码显示,账户地址Hash算法和2015年成为SHA3标准算法的算法有关联,不过,以太坊使用的和SHA3 256不同,是在NIST改动后才成为SHA3算法的,在最新版本1.1.1里,只有标准的SHA3 256,但是从开发角度讲,有时要对不同算法进行细致区分。
typedef struct {
uint64_t A[5][5];
size_t block_size; /* cached ctx->digest->block_size */
size_t md_size; /* output length, variable in XOF */
size_t num; /* used bytes in below buffer */
unsigned char buf[KECCAK1600_WIDTH / 8 - 32];
unsigned char pad;
} KECCAK1600_CTX;
static int init(EVP_MD_CTX *evp_ctx, unsigned char pad)
{
KECCAK1600_CTX *ctx = evp_ctx->md_data;
算法差异处理
两种算法之间相差的只有一个,这其实是具有特殊作用的pad。从实现角度看,pad存放在特定位置。若要使用相关实现,就得对SHA3 256的pad进行修改。有一位从事区块链开发的张师傅,他曾花时间研究这种改动,目的是确保开发项目顺利进行。
BIGNUM* privatekey = BN_new();
BIGNUM* n = BN_new();
BN_CTX *bn_ctx = BN_CTX_new();
const EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1);
EC_GROUP_get_order(group, n, bn_ctx);
BN_rand_range(privatekey, n);
EC_POINT *publickey = EC_POINT_new(group);
EC_POINT_mul(group, publickey, privatekey, nullptr, nullptr, bn_ctx);
unsigned char **buf = (unsigned char **)malloc(8);
size_t size = EC_POINT_point2buf(group, publickey, POINT_CONVERSION_UNCOMPRESSED, buf, bn_ctx);
生成地址过程
首先对EC相关内容做初始化操作,接着生成公钥和私钥。然后开展EVP相关的初始化工作,随后更改pad。因为头文件里没有所需的结构体定义,所以要从源码复制。最后把公钥传给EVP,生成结果后取后面的20个字节,这就成了以太坊账户地址。通过这样严谨的步骤,一个个以太坊账户地址诞生了。
const EVP_MD* evp_md = EVP_sha3_256();
EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_new();
EVP_DigestInit(evp_md_ctx, evp_md);
看完这些内容后,你是否思考过,倘若未来椭圆曲线体系出现新规则,这会给以太坊账户体系带来怎样的影响,不妨在评论区说说你的看法,同时也别忘了给这篇文章点赞并分享。
struct EVP_MD_CTX_t {
const EVP_MD *digest;
ENGINE *engine; /* functional reference if 'digest' is
* ENGINE-provided */
unsigned long flags;
void *md_data;
/* Public key context for sign/verify */
EVP_PKEY_CTX *pctx;
/* Update function: usually copied from EVP_MD */
int(*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
} /* EVP_MD_CTX */;
struct KECCAK1600_CTX {
uint64_t A[5][5];
size_t block_size; /* cached ctx->digest->block_size */
size_t md_size; /* output length, variable in XOF */
size_t num; /* used bytes in below buffer */
unsigned char buf[1600 / 8 - 32];
unsigned char pad;
};
暂无评论
发表评论