EOSIO
In eos the initial value of nonce is 1
static int extended_nonce_function( unsigned char *nonce32, const unsigned char *msg32,
const unsigned char *key32, unsigned int attempt,
const void *data ) {
unsigned int* extra = (unsigned int*) data;
(*extra)++; //这是初始计数器值,从0变到1
return secp256k1_nonce_function_default( nonce32, msg32, key32, *extra, nullptr );
}
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
secp256k1_rfc6979_hmac_sha256_t rng;
unsigned int i;
secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0);
for (i = 0; i <= counter; i++) { //因为此计数器在第一次被设置为1,所以循环将执行两次,并且第一个K被忽略!!!!
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
}
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
return 1;
}
EOSJS
-
eosjs-ecc算法也是OK的,它提供了一个有效的签名 (一个哈希可以有很多有效的签名,而不仅仅是一个)。唯一的区别是eos从第二个k开始搜索,而eosjs-ecc从第一个k开始搜索,因此有时它们会产生不同的结果(但这些结果都是合法结果)。
-
可以调整eosjs-ecc循环代码以忽略第一个k,使其严格按eos的方式工作
-
在signature.js中的
signHash
方法中,将初始随机数更改为1:
-
在ecdsa.js的
deterministicGenerateK
方法中,稍微更改循环结构:
它现在与eos产生完全相同的签名
-
结论: 签名不是唯一的, 但始终能恢复出相同的公钥。给定哈希和私钥在此链上的签名不需要匹配,它们只需要规范且有效。
https://github.com/EOSIO/eosjs-ecc/issues/20