主页 > imtoken钱包收款地址 > 了解以太坊的椭圆曲线签名
了解以太坊的椭圆曲线签名
原理 以太坊数字签名与比特币的关系
以太坊数字签名几乎完全遵循比特币的数字签名算法ECDSA-secp256k1。 只是hash的生成方式不同,后面会讲到。 ECDSA-secp256k1 是一种非对称加密算法。
什么是ECDSA
以太坊数字签名算法采用椭圆曲线数字签名算法,简称ECDSA。 其中,EC是“Elliptic Curve”的缩写,DSA是“Digital Signature Algorithm”的缩写。
什么是 secp256k1
椭圆曲线算法简单来说就是用X和Y坐标画一条曲线。 如何绘制这条曲线需要很多参数来确定。 以太坊使用一组称为 secp256k1 的参数来确定椭圆的形状。 因此,以太坊的签名算法全称是ECDSA-secp256k1。
什么是非对称加密
什么是对称加密,什么是非对称加密? 简单的说,只有一把钥匙就是对称加密,用于加密和解密。 有两个密钥,是非对称加密。 一个密钥用于加密,另一个用于解密。 与对称加密算法相比,非对称加密的优点是不需要将加密密钥暴露在网络上,在机制上更加安全; 缺点是加密效率远低于对称加密。 因此,非对称加密一般只用于数字签名等数据量较小的加密操作。
常见的非对称加密算法除了椭圆加密算法外,还有大名鼎鼎的RSA。 椭圆加密与RSA的区别在于:
私钥
以太坊的私钥是一个32字节的数字,取值范围为1到0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140。这个数字可以通过伪随机算法(PRNG)生成。 其实0也是一个合法的私钥,只不过是一个特殊的私钥,以太坊的创世区块就是由这个私钥生成的。
公钥
以太坊的未压缩公钥是一个 65 字节的数字,它继承自比特币。 但是以太坊只使用了其中的 64 个。 64个字节中,32个字节表示椭圆曲线的X坐标,32个字节表示椭圆曲线的Y坐标。 这个 XY 坐标是通过 ECDSA-secp256k1 从私钥中导出的。 因此,椭圆曲线算法的公钥是从私钥计算出来的。 另一方面,用公钥推导出私钥几乎是不可能的,这也是以太坊和比特币存在的基础。 如果有一天计算机技术有了很大的飞跃,比如量子计算机的普及,现有链上所有账户的私钥都会暴露。 当然,区块链技术本身会继续发展。
散列
Hash也可以形象地称为“汇总”。 即无论消息有多大,都可以生成一个固定长度的“摘要”,通过这个“摘要”可以验证消息是否被篡改。 一旦消息被修改了一个字节,“摘要”检查就会失败。
比特币的哈希算法使用 SHA2-256。 与 SHA1 相比,SHA2 只是扩展了散列的字节数。 目前SHA1已经被攻破,SHA2被攻破只是时间问题。
以太坊的哈希算法使用新的 SHA3-256。 与SHA1和SHA2不同,SHA3并不是简单地扩展字节数,而是使用了新的Keccak算法。 相同字节宽度的SHA3比SHA2更安全。
地址
以太坊的地址是公钥经过一系列哈希和变换后以太坊私钥生成原理,通过Base58编码生成的字符串。 不描述该过程。 Base58编码与Base64类似,都是使用“可读符号”来表示二进制数据。与Base64相比,Base58去除了一些容易引起视觉混淆的字母和数字。
符号
签名实际上是用私钥加密消息的散列。 当一个以太坊节点向另一个节点发送消息时,它用自己的私钥对消息的哈希进行签名,然后将签名和消息本身发送给对方。
流程如图所示:
图片.png
验证签名
节点收到对方的消息和签名后,首先会执行“恢复”动作,利用消息和签名推导出对方的公钥。 然后使用消息的公钥、签名和哈希值计算出一个名为“r”的值。 这个 r 是签名的一部分。 要验证签名,请将计算出的 r 与签名中携带的 r 进行比较。 如果一致就通过验证。
流程如图所示:
图片.png
代码
以太坊项目 geth 有两套 ECDSA-secp256p1 实现。 一套是纯围棋的,一套是基于C库的。 底层算法不是以太坊开发者写的,采用开源世界的主义。
执行
界面源代码位于 crypto/signature_nocgo.go。 这个文件只是一个包装器,真正的实现调用了第三方的bitcoin go项目,源码在vendor//github.com/bitcsuite/bitcd。
C实现
接口源码在crypto/signature_cgo.go。 这也是一个包装器,下一个调用是 crypto/secp256k1/。 这还是一个wrapper以太坊私钥生成原理,再往下就是Bitcoin C语言项目的libsecp256k1库。
API及其功能
signature_nocgo.go和signature_cgo.go的接口是一样的,如下:
//通过消息的哈希和签名恢复公钥
func Ecrecover(hash, sig []byte) ([]byte, error) {}
//通过哈希和私钥计算ECDSA签名
func Sign(hash []byte, prv *ecdsa.PrivateKey) {}
//通过公钥,哈希校验签名
func VerifySignature(pubkey, hash, signature []byte) bool {}
//将33字节的公钥解压成65字节公钥
func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {}
//将65字节非压缩公钥压缩称33字节压缩公钥
func CompressPubkey(pubkey *ecdsa.PublicKey) {}