This case we will use the PyNaCl (Networking and Cryptography) library, and which is a Python binding to libsodium. We will produce a random 32 byte (256-bit) private key and use Ed25519 to sign a message. The public key is then used to check the signature.
Sodium: NaCl - Ed25519 signature |
Outline
Key generation
Alice generates a random 32-byte secret key (\(sk\)) and then creates a public key of:
\(pk=sk \cdot B\)
and where \(B\) is the base point of the curve.
Signing
Alice creates a SHA-512 hash of her private key:
\(h=\textrm{HASH}(sk)\)
Create \(r\) from the upper 32 bytes of hash and the message:
\( r = \textrm{HASH}(h[32:] \: || \: m))\)
And where "||" represents a concatenation of the byte array values. Next she matches \(r\) onto curve with:
\(R=r \cdot B\)
Next Alice computes \(s\) with:
\(s=r + (\textrm{HASH}(R \: || \: pk \: || \: m)) \cdot sk\)
The signature is (\(R,s\)). The values of \(R\) and \(s\) are 32 bytes long, and thus the signature is 64 bytes long.
Verifying
Bob creates \(S\) using \(R\), \(pk\) and \(m\):
\(S =\textrm{HASH}(R \: || \: pk \: || \: m) \)
And next creates two verification values:
\(v_1=s \cdot B\)
\(v_2=R+ pk \cdot S\)
If \(v_1==v_2\) the signature checks. This is because:
\(v_1=sB = (r + (\textrm{HASH}(R \: || \: pk \: || \: m)) \cdot sk) \cdot B = rB + sk \cdot B \cdot (\textrm{HASH}(R \: || \: pk \: || \: m))= R+ pk \cdot S = v_2 \)
Overall, we just need point multiplication and point addition.
Coding
The code is:
import nacl.signing import binascii import sys from os import urandom msg='hello' if (len(sys.argv)>1): msg=str(sys.argv[1]) message=msg.encode() key_seed = urandom(32) private_key = nacl.signing.SigningKey(key_seed) signed_message = private_key.sign(message) public_key = private_key.verify_key print ("Message: ",message) print ("\nPrivate key: ",binascii.hexlify(private_key.encode())) print ("Signed: ",binascii.hexlify(signed_message)) print ("Public key: ",binascii.hexlify(public_key.encode())) rtn=public_key.verify(signed_message.message,signed_message.signature) if (rtn==message): print ("Signature valid") else: print ("Signature invalid")
A sample run is:
Message: b'hello' Private key: b'2756d2a99c7c866f8275f1758670598cb6f8ecbd502f5a9347f75205b7409822' Signed: b'7c4a5193576bf35777868fc7e63406c9a9f13f5d7e165399337d449f59da849b8efeb675f7e95edcb58d28dbb8d6d44fd1130b16b0c0f7de97bbd46d853fc30a68656c6c6f' Public key: b'2ca17f36e25320747bb6b35e2c4e81f427b6fcf2333025009a20cf0fa63a3c1c' Signature valid