【⽐特币】椭圆曲线数字签名算法-ECDSA
参考:
原理篇:
实验篇:
Makefile
.PHONY:all
all:
gcc -I/d/workspace/github/altcoin/bitcoin-3rd/ssl/include -o sigvery -g -O0 sigvery.c -L/d/workspace/github/altcoin/bitcoin-3rd/ssl/lib -lssl -lcrypto -lgdi32 Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslconf.h>
#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
int main(int argc, char * argv []){
// First step: create a EC_KEY object (note: this part is not ECDSA specific)
miss worldint ret;
int nid;
ECDSA_SIG *sig;
EC_KEY *eckey;
unsigned char digest [20];
memt(digest, 0xaa, sizeof(digest));// 测试⽤的假HASH
nid = OBJ_sn2nid("cp256k1");
eckey = EC_KEY_new_by_curve_name(nid);
if (eckey == NULL)
{
/* error */
perror("EC_KEY_new_by_curve_name");
}
maggyif (!EC_KEY_generate_key(eckey))
{
/* error */
}
el
{// 打印⼀下ec的私钥和公钥
EC_KEY_print_fp(stdout, eckey, 0);
}
ture love// Second step: compute the ECDSA signature of a SHA-1 hash value using ECDSA_do_sign
sig = ECDSA_do_sign(digest, 20, eckey);// 签名
if (sig == NULL)如何跟客户沟通
{
/* error */
perror("ECDSA_do_sign");
}
el
{// 打印⼀下签名,r和s
printf("Signature:\n\tr=%s\n\ts=%s\n", BN_bn2hex(sig->r), BN_bn2hex(sig->s));
}
// Third step: verify the created ECDSA signature using ECDSA_do_verify
ret = ECDSA_do_verify(digest, 20, sig, eckey);// 验证
if (ret == -1)
{
/* error */
perror("ECDSA_do_verify");
}
el if (ret == 0)monsoon
{
2012年浙江高考数学
/* incorrect signature */nbcs是什么意思的缩写
printf("Verified Failure\n");
}
el /* ret == 1 */
{
/* signature ok */
printf("Verified OK\n");
}
return 0;
}
测试:
HASH=0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; // 20个字节的0xaa
$ ./
Private-Key: (256 bit)
two dozen
priv:
00:95:55:33:26:d8:92:cd:58:d7:7b:71:b8:02:29:
36:41:9a:22:e9:f0:21:72:02:a7:fc:1e:05:a3:f5:
6e:f4:ec
pub:
04:76:91:81:fd:2e:44:e0:17:03:b3:53:7d:55:fe:
e2:f5:6a:89:d1:5b:2c:e2:06:83:6a:e5:64:b6:4b:
07:76:8c:8b:df:57:7b:75:7b:f6:fb:9c:44:6f:1b:
f6:56:ff:ac:ed:2f:65:a9:49:81:ba:af:90:13:8f:
96:a3:9e:83: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 (uncompresd):
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)hunted
Signature:
r=F0AB42A05A1C7CB18EF50A0E63CF287B3604A3741D6875DADE9031E648055E7D
s=4C556EDC930313C67286A7B7AD7BC336FB39C0BA4BC42BE801FBBE8CBDCD0012
Verified OK
⽐特币⽬前使⽤ECDSA对货币的所有权进⾏鉴定,当然前提是对于付款地址是椭圆曲线算法的公钥(cp256k1 for bitcoin)。
如果是puzzle类型等⾮标准的付款⽅式,那么resolve的⽅式就不是签名/验证的形式了,那就要看脚本的设置到底需要什么的推理前提了。关于签名算法的细节可以参考例⼦。
⽐特币的源代码使⽤CECKey结构对openssl的ec算法进⾏了封装。
在此基础上衍⽣了其他密钥管理对象,CPubKey, CKeyID, CScriptID, CPrivKey, CKey
1) CKey
对openssl中的ecdsa算法的基本封装,是整个算法的核⼼。
CKey可以导⼊通过SetPrivKey()/GetPrivKey()导⼊/导出openssl格式的私钥。
// Initialize from a CPrivKey (rialized OpenSSL private key data).
bool SetPrivKey(const CPrivKey &vchPrivKey, bool fCompresd);
// Convert the private key to a CPrivKey (rialized OpenSSL private key data).
// This is expensive.
CPrivKey GetPrivKey() const;
CKey可以通过GetPubKey()导出公钥(压缩格式或者⾮压缩格式的,根据内部标记来决定)
// Compute the public key from a private key.
// This is expensive.
CPubKey GetPubKey() const;
CKey可以通过Sign()来签署消息摘要
// Create a DER-rialized signature.
bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const;
2) CPubKey
对openssl中的ecdsa算法的公钥的基本封装,可以由CKey的成员函数计算得到。
pyreCPubKey可以通过GetID()调⽤来计算得到该公钥对应的索引(也就是该公钥的hash256/ripemd160的hash)
// Get the KeyID of this public key (hash of its rialization)
CKeyID GetID() const {
return CKeyID(Hash160(vch, vch+size()));
}
CPubKey可以通过Verify()来验证CKey的签名
// Verify a DER signature (~72 bytes).
// If this public key is not fully valid, the return value will be fal.
bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const;
3)CScript
对⽀付脚本的状态机的封装
CScript可以通过GetID()来获取序列化的脚本的索引(hash值)