ECDSA vs. EdDSA

1. 引言

前序博客:

若对网络安全感兴趣,建议了解下:

  • ECDSA 代表Elliptic Curve Digital Signature Algorithm(椭圆曲线数字签名算法)
  • EdDSA 代表Edwards-curve Digital Signature Algorithm(Edwards曲线数字签名算法)

二者均可用于创建数字签名。
Bob 使用其私钥签署消息,然后 Alice 使用消息、签名和 Bob 的公钥来验证该签名。一旦 Bob 签署了消息,就不可能基于该签名来修改密钥或消息——那样的修改后的签名将无法验证通过。
在这里插入图片描述

上图展示了椭圆曲线签名算法概要:

  • Bob 使用其私钥 (sk) 对消息M进行哈希签名,并生成签名:(r,s)。
  • 签名(r,s)与消息M一起发送给 Alice。
  • Alice 计算消息M的哈希,并和签名 (r,s) 以及 Bob 的公钥 (pk)一起进行签名验证。
    • 若验证通过,Alice 就知道 Bob 签署了该消息。

ECDSA 和 EdDSA有什么区别呢?什么时候应该使用 ECDSA 而不是 EdDSA,反之亦然。

  • 对于与比特币和以太坊兼容的东西,ECDSA 提供了最佳解决方案。
  • 不幸的是,ECDSA依赖于要创建的随机 nonce 值,若 nonce 不是随机的,则会显著降低签名的安全性。
  • EdDSA 的速度性能与 ECDSA 大致相同,但EdDSA自然支持密钥聚合,以便在签名过程中进行密钥聚合。原因在于EdDSA基于 Schnorr 签名方法。

ECDSA 已存在二十多年,最早由Don Johnson、Alfred Menezes 和 Scott Vanston 2001年论文The Elliptic Curve Digital Signature Algorithm (ECDSA) 中提出:
在这里插入图片描述

2011 年,Ed25519 被提出作为一种快速、安全的数字签名方法(见 Daniel J. Bernstein、Niels Duif、Tanja Lange、Peter Schwabe 和 Bo-Yin Yang 2011年论文High-speed high-security signatures):
在这里插入图片描述
关于签名的更多信息见:

1.1 EdDSA 和 ECDSA 的要点

EdDSA 和 ECDSA 的关键点有:

  • 1)Ed25519 由 Daniel J. Bernstein、Niels Duif、Tanja Lange、Peter Schwabe 和 Bo-Yin Yang 于 2011 年提出,而 ECDSA 由 Don Johnson、Alfred Menezes 和 Scott Vanstone 于 2001 年左右提出。
  • 2)ECDSA 使用 secp256k1 曲线,EdDSA 使用 Curve 25519。
  • 3)比特币和以太坊使用 ECDSA,而 IOTA 使用 EdDSA。【见IOTA EdDSA Support,2021年8月已用EdDSA签名替代了Winternitz One Time Signature (W-OTS)方案。】
  • 4)EdDSA 采用 Schnorr 签名方法,目前Schnorr签名已过专利保护期。EdDSA 支持签名中的密钥聚合,也支持多方签名的聚合。
  • 5)为了提高安全性,ECDSA 支持 521-bit 曲线(P521),而 EdDSA 支持 X448。
  • 6)ECDSA 在签名创建过程中会创建一个随机 nonce 值,而 EdDSA 则不会。在 ECDSA 中,需要小心确保不会重复使用此 nonce 值,且该nonce值是随机的。
  • 7)ECDSA 签名每次都会根据所使用的随机数而改变,而 EdDSA 签名对于同一组密钥和同一条消息不会改变。
  • 8)ECDSA 经常被用来保持与比特币和以太坊的兼容性。
  • 9)ECDSA 公钥是 (x,y) 坐标,因此有 512 位(对于 secp256k1),而 Ed25519 仅使用点的 y 坐标值,因此有 256 位。
  • 10)ECDSA 和 EdDSA 通常具有相同的性能和安全级别。
  • 11)EdDSA 是一种确定性签名(意味着总是针对相同的私钥和消息获得相同的签名),而 ECDSA 是非确定性的。
  • 12)EdDSA 和 ECDSA 的安全性与 128 位 AES 和 3K RSA 相当。
  • 13)EdDSA 对侧信道攻击具有相当强的免疫力。

2. 了解Schnorr签名

1989 年 2 月,德国数学家、密码学家 Claus Schnorr 提交了一项专利,但尚未被授予任何人。该专利有 11 项权利要求,允许为多个signers合并数字签名(见专利文件 Method for identifying subscribers and for generating and verifying electronic signatures in a data exchange system):
在这里插入图片描述

使用 Schnorr 签名,为消息 (M) 的哈希值创建签名 (R,s):

  • 首先生成私钥 (x),然后从椭圆曲线 (G) 上的某个点派生公钥,得到:
    P=x⋅G
  • 接下来,选择一个随机值(k)来得到R的签名值:
    R=k⋅G
  • 那么 s 的值就是:
    s=k−Hash(M,R)⋅x
  • 对 M 的签名是 (s,R),公钥是 P。

Schnorr验签过程为:

  • 计算P⋅Hash(M,R)+s⋅G
    对应为: x⋅G⋅Hash(M,R)+(k−Hash(M,R)⋅x)⋅G
    即:
    x⋅G⋅Hash(M,R)+k⋅G−Hash(M,R)⋅x⋅G=k⋅G
  • k⋅G 的值等于 R,因此若结果与 R 相同,则签名通过。

3. EdDSA 和 Ed25519

Edwards-curve Digital Signature Algorithm (EdDSA) 使用 Twisted Edwards 曲线增强 Schnorr 签名来创建数字签名。

总体而言,EdDSA比许多其他数字签名方法更快,且安全性更强。

EdDSA 的实例之一是:

  • Ed25519,其基于 Curve 25519。Ed25519可提供大约128 位的安全性并生成 64 字节的签名值 (R,s)。除此之外,Ed25519还有 32 字节的公钥和私钥值。
    在这里插入图片描述

以下是 Golang 代码(EdDSA and Ed25519 in Golang):

package main

import (
	"crypto/ed25519"

	"encoding/base64"
	"fmt"
	"os"
)

func Base64Encode(message []byte) []byte {
	b := make([]byte, base64.StdEncoding.EncodedLen(len(message)))
	base64.StdEncoding.Encode(b, message)
	return b
}

func main() {

	msg := "Hello 123"

	argCount := len(os.Args[1:])
	if argCount > 0 {
		msg = os.Args[1]
	}

	publ, priv, _ := ed25519.GenerateKey((nil))

	m := []byte(msg)

	sig := ed25519.Sign(priv, m)

	fmt.Printf("=== Message ===\n")
	fmt.Printf("Msg: %s\nHash: %x\n", msg, m)
	fmt.Printf("\n=== Public key ===\n")
	fmt.Printf("Public key: %x\n", publ)
	fmt.Printf("   Public key (Base64): %s\n", Base64Encode(publ))
	fmt.Printf("\n=== Private key ===\n")
	fmt.Printf("Private key: %x\n", priv[0:32])
	fmt.Printf("   Private key (Base64): %s\n", Base64Encode(priv[0:32]))
	fmt.Printf("   Private key (Base64) Full key: %s\n", Base64Encode(priv))
	fmt.Printf("   Private key (Full key): %x\n", priv)
	fmt.Printf("\n=== Signature (R,s) ===\n")
	fmt.Printf("Signature: R=%x s=%x\n", sig[0:32], sig[32:64])
	fmt.Printf("   Signature (Base64)=%s\n\n", Base64Encode(sig))

	rtn := ed25519.Verify(publ, m, sig)

	if rtn {
		fmt.Printf("Signature verifies")
	} else {
		fmt.Printf("Signature does not verify")
	}
}

使用“Hello”消息运行的以上代码,对应有(EdDSA and Ed25519 in Golang):

=== Message ===
Msg: Hello
Hash: 48656c6c6f

=== Public key ===
Public key: c3903a26c73a433554325859c963056acd2d503fc36313ae21647f911e723fab
   Public key (Base64): w5A6Jsc6QzVUMlhZyWMFas0tUD/DYxOuIWR/kR5yP6s=

=== Private key ===
Private key: fc225cb6dd8969541e57754b4120b51e6a92673107c7c8e1dc25a7a3e6b1066b
   Private key (Base64): /CJctt2JaVQeV3VLQSC1HmqSZzEHx8jh3CWno+axBms=
   Private key (Base64) Full key: /CJctt2JaVQeV3VLQSC1HmqSZzEHx8jh3CWno+axBmvDkDomxzpDNVQyWFnJYwVqzS1QP8NjE64hZH+RHnI/qw==
   Private key (Full key): fc225cb6dd8969541e57754b4120b51e6a92673107c7c8e1dc25a7a3e6b1066bc3903a26c73a433554325859c963056acd2d503fc36313ae21647f911e723fab

=== Signature (R,s) ===
Signature: R=fbee75ddd533296a9ebacbe653a3335d1b9a99d6e6c7941d4651e04a6268ad2e s=086b3da235c4f4e426d1a2e76a731c0a81844d98fe59f412abd869fb3008d00d

   Signature (Base64)=++513dUzKWqeusvmU6MzXRuamdbmx5QdRlHgSmJorS4Iaz2iNcT05CbRoudqcxwKgYRNmP5Z9BKr2Gn7MAjQDQ==

Signature verifies

其中:

  • Ed25519签名长度为 64 字节,其中R值占 32 字节,s值占 32 字节。
  • 公钥长度也是 32 字节,私钥长度为 32 字节。
  • 总体而言,Ed25519 产生的签名大小是最小的,公钥和私钥的大小都很小。
  • 在更加分布式的环境中,使用 Schnorr 签名支持将密钥拆分为shares,并允许不同的各方聚集在一起并生成其签名部分。此方法支持删除私钥,然后将私钥拆分为secret shares。

Ed25519 用于数字签名的好处有:

  • 签名速度超快:benchmark显示,在流行的 CPU 上签名只需不到 90K 个周期
  • 验证速度超快:benchmark显示,在流行的 CPU 上,验签所需的时间不到 300K 个周期,批量验签的速度甚至更快(每个签名所需的时间不到 134K 个周期)。
  • 密钥生成速度超快:在流行的 CPU 上只需不到 6K 个周期。
  • 安全级别高:Ed25519 与 128 位 AES、NIST P256 和 3K RSA 相当。
  • 抗碰撞。哈希碰撞不会破坏 Ed25519。
  • 小签名:Ed25519签名只有512位长(64字节)。
  • 小密钥和派生公钥:Ed25519 密钥只有 256 位长(32 字节),且可从私钥派生出公钥。
  • Ed25519 签名是确定性的:相同的输入数据将始终导致相同的签名,这与需要随机nonces的 ECDSA 不同。
  • 相当程度上免受旁道攻击。

以下是一些示例:

4. ECDSA

ECDSA 方法比基于 RSA 的 DSA 方法显著提高了签名消息的性能。ECDSA使用椭圆曲线方法加快了整个过程,并支持更小的密钥大小。ECDSA的王冠和荣耀在于中本聪选择在其比特币协议中使用ECDSA,然后被以太坊采用。但ECDSA在签名聚合和分布式环境中密钥拆分方面确实遇到了困难。

ECDSA 中的数学知识为:
在这里插入图片描述

ECDSA签名为 (r,s) pair,并可验签。

  • 与EdDSA不同,ECDSA可使用一系列曲线,而不是使用Curve 25519,如 secp256k1 (P256k1)、P244 和 P521。
    在这里插入图片描述

secp256k1 的安全级别与 Ed25519 大致相同。

  • 在 Ed25591 中,椭圆曲线上某点,只使用 y 坐标点,而在 ECDSA 中,通常为 (x,y) 坐标点。
  • ECDSA公钥(即曲线上的点)长度为 512 位,而私钥长度仅为 256 位。
  • 总体而言,ECDSA 中的公钥比 EdDSA 中的公钥更大。
  • 不过,ECDSA 的主要缺点是其不支持密钥和签名的合并。

ECDSA签名Go代码实例见ECDSA Creation and Verification

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"os"
	"strings"

	"github.com/dustinxie/ecc"
)

func getCurve(s string) elliptic.Curve {
	if strings.Contains(s, "224") {
		return (elliptic.P224())
	} else if strings.Contains(s, "384") {
		return (elliptic.P384())
	} else if strings.Contains(s, "521") {
		return (elliptic.P521())
	}
	return (ecc.P256k1())
}

func main() {

	msg := "Hello 123"
	curveType := ""

	argCount := len(os.Args[1:])
	if argCount > 0 {
		msg = os.Args[1]
	}
	if argCount > 1 {
		curveType = os.Args[2]
	}

	pubkeyCurve := getCurve(curveType)
	m := []byte(msg)
	digest := sha256.Sum256(m)

	privatekey, _ := ecdsa.GenerateKey(pubkeyCurve, rand.Reader)

	pubkey := privatekey.PublicKey

	r, s, _ := ecdsa.Sign(rand.Reader, privatekey, digest[:])

	fmt.Printf("=== Message ===\n")
	fmt.Printf("Msg=%s\nHash=%x\n", msg, digest)
	fmt.Printf("\n=== Private key ===\n")
	fmt.Printf("Private key=%x\n", privatekey.D)
	fmt.Printf("Curve=%s\n", privatekey.Curve.Params().Name)
	fmt.Printf("Bit size=%d\n", privatekey.Curve.Params().BitSize)
	fmt.Printf("Base point (G) =(%d, %d)\n", privatekey.Curve.Params().Gx, privatekey.Curve.Params().Gy)
	fmt.Printf("Prime=%d, Order=%d", privatekey.Curve.Params().P, privatekey.Curve.Params().N)
	fmt.Printf("\n=== Public key (X,Y) ===\n")
	fmt.Printf("X=%s Y=%s\n", pubkey.X, pubkey.Y)
	fmt.Printf("  Hex: X=%x Y=%x\n", pubkey.X.Bytes(), pubkey.Y.Bytes())
	fmt.Printf("\n=== Signature (R,S) ===\n")
	fmt.Printf("R=%s S=%s\n", r, s)
	fmt.Printf(" Hex: R=%x S=%x\n", r, s)

	rtn := ecdsa.Verify(&pubkey, digest[:], r, s)

	if rtn {
		fmt.Printf(\n"Signature verifies")
	} else {
		fmt.Printf("\nSignature does not verify")
	}
}

对应运行结果为:

=== Message ===
Msg=Hello 123
Hash=859e38d581e214dc7c8c871c425642913363a829065cf4acddd120ed5391b04b

=== Private key ===
Private key=b3645f2efea9a96d28cbeb5bf8a5304a3dc96b2a42bee21c0b3aaa88f595df2d
Curve=P-256k1
Bit size=256
Base point (G) =(55066263022277343669578718895168534326250603453777594175500187360389116729240, 32670510020758816978083085130507043184471273380659243275938904335757337482424)
Prime=115792089237316195423570985008687907853269984665640564039457584007908834671663, Order=115792089237316195423570985008687907852837564279074904382605163141518161494337
=== Public key (X,Y) ===
X=77007236596272499552697218405908714888874625059778411542685725622785792316534 Y=20745252821220973789342590850065442758134973002375340605949893038975196614597
  Hex: X=aa408d244da8a2ea673213ef63536ea96486ce0412a5294c9cdf0959cc689476 Y=2ddd65a19ed17f361b0381a72713f740b63d4fdca059427c389239da39004fc5

=== Signature (R,S) ===
R=33027995512220841690000083421269061534408622570666620793995266029032826750381 S=44867240085578618664628913670877492263668786345184239470907981535519639811276
 Hex: R=49052ed8fcf1903f530bda10ea9b578b6bb77487ea6b22b5558fc68524e045ad S=6331f53ce5e1a64e4043712631aeeb3f5c0ed753140a0fd76a8c5367e69b34cc
Signature verifies

更多ECDSA签名例子见:

参考资料

[1] 2024年5月19日博客 A Bluffers Guide to EdDSA and ECDSA

附录 各区块链项目背后曲线、签名方案总结

2021年2月总结 Cryptography behind the top 100 cryptocurrencies中总结了当时市值前100 区块链项目背后的所用的签名算法、曲线信息,其中:

  • 共有74个项目使用ECDSA和secp256k1曲线,包括比特币、以太坊、和 48个ERC20 tokens。
  • 10个项目使用EdDSA和curve25519,如Stellar、Cardano、Elrond、Solana等。
  • 8个项目使用了多种签名算法和曲线(通常为既有ECDSA/secp256k1,也有EdDSA/curve25519),如Polkadot、Tezos、NEAR等。
NameSymbolSigning AlgorithmCurveNotes
BitcoinBTCECDSAsecp256k1
EthereumETHECDSAsecp256k1
TetherUSDTEthereum ERC20 token
PolkadotDOTECDSA, Schnorr, EdDSAcurve25519, ristretto25519, secp256k1
XRPXRPECDSA, EdDSAcurve25519, secp256k1** is the default
CardanoADAEdDSAcurve25519
LitecoinLTCECDSAsecp256k1
Bitcoin CashBCHECDSAsecp256k1
ChainlinkLINKEthereum ERC20 token
StellarXLMEdDSAcurve25519
Binance CoinBNBECDSAsecp256k1
USD CoinUSDCEthereum ERC20 token
Wrapped BitcoinWBTCEthereum ERC20 token
Bitcoin SVBSVECDSAsecp256k1
EOSEOSECDSAsecp256k1
MoneroXMREdDSA*, Bulletproofscurve25519* non-standard hashing algorithm, uses Keccak
AaveAAVEEthereum ERC20 token
TronTRXECDSAsecp256k1
VeChainVETECDSAsecp256k1
NEMXEMEdDSAcurve25519
SynthetixSNXEthereum ERC20 token
CosmosATOMECDSAsecp256k1
Theta NetworkTHETAECDSAsecp256k1
UniswapUNIEthereum ERC20 token
NEONEOECDSANIST P-256
Crypto.com CoinCROECDSAsecp256k1
OKBOKBEthereum ERC20 token
Celsius NetworkCELEthereum ERC20 token
cUSDCCUSDCEthereum ERC20 token
cETHCETHEthereum ERC20 token
DaiDAIEthereum ERC20 token
LEO TokenLEOEthereum ERC20 token
IOTAMIOTA**Winternitz OTS【2021年8月,已迁移至EdDSA签名方案】 **
TezosXTZECDSA, EdDSAsecp256k1, curve25519, NIST P-256tz1: EdDSA, tz2: ECDSA/secp256k1, tz3: ECDSA/NIST P-256
ElrondEGLDEdDSAcurve25519
MakerMKREthereum ERC20 token
Binance USDBUSDEthereum ERC20 token
DogecoinDOGEECDSAsecp256k1
DashDASHECDSAsecp256k1
Huobi TokenHTEthereum ERC20 token
FilecoinFILECDSAsecp256k1
ZcashZECECDSA, ZK-SNARKs*secp256k1, BLS12-381-JubJub** for shielded/anonymous transactions
AvalancheAVAXECDSAsecp256k1
Yearn FinanceYFIEthereum ERC20 token
KusamaKSMECDSA, EdDSA, Schnorrsecp256k1, curve25519, ristretto25519
Ethereum ClassicETCECDSAsecp256k1
SolanaSOLEdDSAcurve25519
cDAICDAIEthereum ERC20 token
FTX TokenFTTEthereum ERC20 token
SushiSUSHIEthereum ERC20 token
CompoundCOMPEthereum ERC20 token
Huobi BTCHBTCEthereum ERC20 token
ZilliqaZILEC-Schnorrsecp256k1
Hedera HashgraphHBARECDSA, EdDSA, RSA*NIST P-384, curve25519* 3072 bit RSA
UMAUMAEthereum ERC20 token
DecredDCREdDSA, EC-Schnorr*curve25519, secp256k1* non-standard
WavesWAVESEdDSAcurve25519
NearNEARECDSA, EdDSAsecp256k1, curve25519
The GraphGRTEthereum ERC20 token
RENRENEthereum ERC20 token
Paxos StandardPAXEthereum ERC20 token
LoopringLRCEthereum ERC20 token
OMG NetworkOMGEthereum ERC20 token
renBTCRENBTCEthereum ERC20 token
OntologyONTECDSANIST P-256
ICONICXECDSAsecp256k1
BlockstackSTXECDSAsecp256k1
THORChainRUNEBinance BEP2 token
TrueUSDTUSDEthereum ERC20 token
NanoNANOEdDSA*curve25519* uses Blake2b-512 instead of SHA-512 in key derivation
TerraLUNAECDSAsecp256k1
NEXONEXOEthereum ERC20 token
AlgorandALGOEdDSAcurve25519
Basic Attention TokenBATEthereum ERC20 token
0xZRXEthereum ERC20 token
DigiByteDGBECDSAsecp256k1
Reserve Rights TokenRSREthereum ERC20 token
Curve DAO TokenCRVEthereum ERC20 token
Enjin CoinENJEthereum ERC20 token
Aave LinkALINKEthereum ERC20 token
Nexus MutualNXMEthereum ERC20 token
HorizenZENECDSAsecp256k1
HUSDHUSDEthereum ERC20 token
IOSTIOUSTECDSA, EdDSAsecp256k1, curve25519
QtumQTUMECDSAsecp256k1
Kyber NetworkKNCEthereum ERC20 token
Bitcoin Cash ABCBCHAECDSAsecp256k1
Energy Web TokenEWTECDSAsecp256k1
SwissBorgCHSBEthereum ERC20 token
AmpleforthAMPLEthereum ERC20 token
BitTorrentBTTTron TRC20 token
QuantQNTEthereum ERC20 token
BalancerBALEthereum ERC20 token
SiacoinSCEdDSAcurve25519
Ocean ProtocolOCEANEthereum ERC20 token
Aave ETHAETHEthereum ERC20 token
TerraUSDUSTECDSAsecp256k1
Voyager TokenVGXEthereum ERC20 token
ArweaveARRSA** 4096 bit RSA
StatusSNTEthereum ERC20 token
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ECDSA.recover is a function in the ECDSA (Elliptic Curve Digital Signature Algorithm) cryptographic system that allows a user to recover the public key from a given signature and message. This function is useful in situations where the public key is unknown but the signature and message are available. The ECDSA algorithm involves three steps: key generation, signature generation, and signature verification. In the key generation step, a private key is generated using a random number generator, and the corresponding public key is derived from the private key. In the signature generation step, a message is hashed and signed using the private key to generate a signature. In the signature verification step, the signature is verified using the public key to ensure that it was generated by the owner of the private key. In some cases, the public key may not be available, but the signature and message are known. In such cases, the ECDSA.recover function can be used to recover the public key from the signature and message. The function takes three inputs: the message, the signature, and the recovery parameter. The recovery parameter is a number between 0 and 3 that specifies which of the four possible public keys should be recovered from the signature. Once the public key is recovered, it can be used to verify the signature and authenticate the message. Overall, ECDSA.recover is a useful function in the ECDSA cryptographic system that allows for public key recovery in situations where it is unknown but the signature and message are available.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值