Ed25519 and Ed448 implement Edwards-curve Digital Signature Algorithm (EdDSA). Ed25519 uses Curve 25519 and SHA-512 and Ed448 uses Curve 448 and SHA-3. For Ed25519 we use 32 byte values for both the private key and the public key, and for X448 we use 57 byte values for both the private key and the public key. In this case, we will run one standard test for private and public keys, and then using random keys for a given messages.
ECDSA using secp256k1 |
Theory
With ECDSA, Alice will sign a message with her private key, and then Bob will use her public key to verify that she signed the message (and that the message has now changed):
Alice signs the message with the following:
- Create a hash of the message \(e=\textrm{HASH}(m)\).
- Let \(h\) be the \(L_{n}\) be the leftmost bits of \(e\), \(L_{n}\) has a bit length of the group order \(N\).
- Create a random number \(k\) which is between 1 and \(N-1\).
- Calculate a point on the curve as \((x_{1},y_{1})=k\times G\).
- Calculate \( r=x_{1} \pmod N \). If \(r=0\), go back to Step 3.
- Calculate \(s=k^{-1}(h+rd_{A}) \pmod N\). If \(s=0\), go back to Step 3.
- The signature is the pair \((r,s)\).
Bob will check with:
- Create a hash of the message \(e=\textrm{HASH}(m)\).
- Let \(h\) be the \(L_{n}\) leftmost bits of \(e\).
- Calculate \(c=s^{-1} \pmod N\)
- Calculate \(u_{1}=h \cdot c \pmod N\) and \(u_{2}=r \cdot c \pmod N\).
- Calculate the curve point (\(x_{1},y_{1})=u_{1}\times G+u_{2}\times Q_{A}\). If \((x_{1},y_{1})=O\) then the signature is invalid.
- The signature is valid if \(r\equiv x_{1}{\pmod {n}}\), invalid otherwise.
(\(x_{1},y_{1})=u_{1}\times G+u_{2}\times Q_{A} = h c G + r c Q_A = c (hG + rQ_A) = \frac{hG + rQ_A} {k^{-1}(h+rd_A) } = \frac{hG + rd_A G} {k^{-1}(h+rd_A) } = \frac{(h + rd_A) G} {k^{-1}(h+rd_A) } = kG \).
The following is an outline of the code:
from ecpy.curves import Curve from ecpy.keys import ECPrivateKey from ecpy.ecdsa import ECDSA import secrets, binascii import sys msg='Test' if (len(sys.argv)>1): msg=str(sys.argv[1]) print("Message:", msg) msg=msg.encode() curve = Curve.get_curve('secp256k1') signer = ECDSA() sk = ECPrivateKey(secrets.randbits(32*8), curve) # sk.d=0xD30519BCAE8D180DBFCC94FE0B8383DC310185B0BE97B4365083EBCECCD75759 pk = sk.get_public_key() print("Private key:", hex(sk.d)) print(f"Public key: ({hex(pk.W.x)},{hex(pk.W.y)}") sig = signer.sign(msg,sk) sig_val=binascii.hexlify(sig).decode() print ("\nSignature: ",sig_val) print (f"\nr: {sig_val[:64]}\ns: {sig_val[64:]}") rtn=signer.verify(msg,sig,pk) rtn=signer.verify(msg,sig,pk) print ("\nVerified: ",rtn)
Private key: 0x970b03db4084ef2dd4e4036c5baa8edb2ceb9ee11ba01de2474218df2bdc8591b1b84c72e7c0de9f2b697d89dd4f8b017874cad90390a690d7 Message: Test Private key: 0x398e293e6f39b7fed75b1c9daea05fd8e8fdbfce1d83587a3d06d8e8f376d5d9 Public key: (0x69e74a944cb20dcfb2898c50f51a5c7c192efa5aae08ae7b07c2d8cb7400211a,0xa80c7d76cdbed41003b587d37ba9a91b1e0008734a86b3164b9160519be2e9a0 Signature: 3045022100a485981a0d51cc58cbef25b113464e758e912e846e428cc16a83a581b97957c0022005b9df8afea030decf437aec1ee83606e8756df57094a9cffd4f2f47f499b8ab r: 3045022100a485981a0d51cc58cbef25b113464e758e912e846e428cc16a83a5 s: 81b97957c0022005b9df8afea030decf437aec1ee83606e8756df57094a9cffd4f2f47f499b8ab Verified: True