EdDSA:签名/验证示例

上一节解释了 EdDSA 签名的工作原理,现在用代码示例来演示。首先介绍如何使用 Ed25519 签名。

Ed25519 签名示例

我们将使用 Python 库 ed25519,它基于 Bernstein 对 Ed25519 签名算法(在 Edwards 形式的 Curve25519 上实现 EdDSA)所作的原始高性能优化 C 实现:

pip install ed25519

接下来,为 Ed25519 密码系统生成私钥和公钥对,对示例消息进行签名,并验证签名:

import ed25519

privKey, pubKey = ed25519.create_keypair()
print("Private key (32 bytes):", privKey.to_ascii(encoding='hex'))
print("Public key (32 bytes): ", pubKey.to_ascii(encoding='hex'))

msg = b'Message for Ed25519 signing'
signature = privKey.sign(msg, encoding='hex')
print("Signature (64 bytes):", signature)

try:
    pubKey.verify(signature, msg, encoding='hex')
    print("The signature is valid.")
except:
    print("Invalid signature!")

运行上述代码示例:https://repl.it/@nakov/Ed25519-sign-verify-in-Python

上述示例代码的输出如下:

Private key (32 bytes): b'1498b5467a63dffa2dc9d9e069caf075d16fc33fdd4c3b01bfadae6433767d93'
Public key (32 bytes):  b'b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde'
Signature (64 bytes): b'6dd355667fae4eb43c6e0ab92e870edb2de0a88cae12dbd8591507f584fe4912babff497f1b8edf9567d2483d54ddc6459bea7855281b7a246a609e3001a4e08'
The signature is valid.

Ed25519 密钥对是随机生成的:先生成 32 字节的随机种子,再从种子派生私钥,最后从私钥派生公钥。密钥生成所用的哈希函数是 SHA-512。

私钥编码为 64 个十六进制数字(32 字节),公钥同样编码为 64 个十六进制数字(32 字节)。EdDSA-Ed25519 签名 {R, s} 为 32 + 32 字节(64 字节,128 个十六进制数字)。

如果尝试验证遭篡改的消息,验证将失败:

try:
    pubKey.verify(signature, "Tampered msg", encoding='hex')
    print("The signature is valid.")
except:
    print("Invalid signature!")

运行上述代码示例:https://repl.it/@nakov/Ed25519-verify-tampered-message-in-Python

上述示例代码的输出符合预期:

Invalid signature!

Ed448 签名示例

下面演示如何使用 Ed448 签名(在 Edwards 形式的 Curve448-Goldilocks 曲线上实现 EdDSA)。

我们将使用 Python 椭圆曲线库 ECPy。它实现了采用 Weierstrass 曲线(如 secp256k1NIST P-256)、Montgomery 曲线(如 Curve25519Curve448),以及扭曲 Edwards 曲线(如 Ed25519Ed448)的 ECC:

pip install ecpy

接下来,为 Ed448 密码系统生成私钥和公钥对

from ecpy.curves import Curve
from ecpy.keys import ECPrivateKey
from ecpy.eddsa import EDDSA
import secrets, hashlib, binascii

curve = Curve.get_curve('Ed448')
signer = EDDSA(hashlib.shake_256, hash_len=114)
privKey = ECPrivateKey(secrets.randbits(57*8), curve)
pubKey = signer.get_public_key(privKey, hashlib.shake_256, hash_len=114)
print("Private key (57 bytes):", privKey)
print("Public key (compressed, 57 bytes): ",
      binascii.hexlify(curve.encode_point(pubKey.W)))
print("Public key (point): ", pubKey)

运行上述代码示例:https://repl.it/@nakov/Ed448-private-public-keys-in-Python

Ed448 密钥对是随机生成的。根据 RFC 8032,Ed448 私钥由 57 字节的随机种子生成;结合 SHAKE256(x, hash_len=114) 哈希函数、EC 点乘法和 Ed448 的特殊密钥编码规则,将其转换为 57 字节的公钥

上述示例代码的输出可能如下:

Private key (57 bytes): ECPrivateKey:
  d: 625d3edeb5cd69b20b0b6387c3522a21d356ac40b408e34fb2f8442e2c91eee3f877afe583a2fd11770567df69178019d6fbc6357c35eefa3e
Public key (compressed, 57 bytes):  b'261d23911e194ed0cb7f9233568e906d6abcf4d60f73451ca807636d8fa6e4ea5ca12f51d240299a0b86a61ccb2174ce4ed2a8c4f7a8cced00'
Public key (point):  ECPublicKey:
  x: cb5aec366d6b3293354418f8abf67bd5aaf46b49ff9c2154fbc14d9ca22fe93b680954f27c10fed3327ef51c8bce5d2522f41fd554731d88
  y: edcca8f7c4a8d24ece7421cb1ca6860b9a2940d2512fa15ceae4a68f6d6307a81c45730fd6f4bc6a6d908e5633927fcbd04e191e91231d26

私钥编码为 114 个十六进制数字(57 字节)。公钥也以压缩形式编码为 114 个十六进制数字(57 字节)。在上述示例中,公钥 EC 点还以未压缩格式(xy 坐标)输出。EdDSA-Ed448 签名 {R, s} 由 57 + 57 字节组成(114 字节,228 个十六进制数字)。

接下来,使用私钥对示例消息进行签名,然后使用公钥验证签名:

msg = b'Message for Ed448 signing'
signature = signer.sign(msg, privKey)
print("Signature (114 bytes):", binascii.hexlify(signature))

valid = signer.verify(msg, signature, pubKey)
print("Valid signature?", valid)

运行上述代码示例:https://repl.it/@nakov/Ed448-sign-verify-in-Python

针对上述 Ed448 密钥对,代码示例的输出为:

Signature (114 bytes): b'5114674f1ce8a2615f2b15138944e5c58511804d72a96260ce8c587e7220daa90b9e65b450ff49563744d7633b43a78b8dc6ec3e3397b50080a15f06ce8005ad817a1681a4e96ee6b4831679ef448d7c283b188ed64d399d6bac420fadf33964b2f2e0f2d1abd401e8eb09ab29e3ff280600'
Valid signature? True

该签名是确定性的:相同消息和相同私钥会产生相同签名。

如果尝试用遭篡改的消息验证同一个签名,验证将失败:

valid = signer.verify(b'Tampered msg', signature, pubKey)
print("Valid signature?", valid)

运行上述代码示例:https://repl.it/@nakov/Ed448-verify-tampered-message-in-Python

上述示例代码的输出符合预期:

Valid signature? False

results matching ""

    No results matching ""