iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
To sign and verify data with Ed25519 in Python, use the cryptography package. Generate an Ed25519PrivateKey, call sign() on the exact bytes you want to protect, derive the public key from the private key, and call verify() with the signature and the same bytes. A valid signature makes verify() return None. An invalid one raises cryptography.exceptions.InvalidSignature.
The API is short. Most failures come from details around it: byte handling, argument order, key formats, and choosing between the plain Ed25519 algorithm and its prehash variant. This guide covers those details in the order you will meet them.
Install the library and run the minimal flow
-
Install the package with
pip install cryptography. Confirm the release you actually have withpip show cryptography. The examples here follow the pyca/cryptography documentation for release 46.0.4. Later releases may change documented details, so check the docs for your installed version before you deploy.Recommended Free Tools
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Save this as
sign_demo.pyand run it withpython sign_demo.py:#1 Best Overall
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey private_key = Ed25519PrivateKey.generate() message = b'my authenticated message' signature = private_key.sign(message) public_key = private_key.public_key() public_key.verify(signature, message) # raises InvalidSignature on failure print('signature length:', len(signature))The last line prints
signature length: 64. Ed25519 signatures are always 64 bytes.
How the sign and verify calls behave
-
Signing takes one argument,
sign(data), which must be a bytes-like object. The return value is the signature. -
Verification takes the signature first and the data second:
verify(signature, data). Reversing these arguments is a common mistake. It fails withInvalidSignatureeven when the key and message are correct.The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Derivation happens on the private key. Call
private_key.public_key()to get the verifying key. Only the public half needs to be shared with the verifier.
The library labels this module as hazardous-materials API. Treat it as a security-sensitive primitive. Use the established library instead of writing curve code for routine application work, and protect private key bytes according to your protocol’s custody and rotation rules. The pyca/cryptography Ed25519 documentation states: “If you do not have legacy interoperability concerns then you should strongly consider using this signature algorithm.”
Encode text deliberately
Ed25519 signs bytes, not Python strings. If your message starts as text, encode it explicitly and keep that exact byte sequence for both signing and verification:
text = 'invoice 1042: total 19.99 EUR'
message = text.encode('utf-8')
signature = private_key.sign(message)
public_key.verify(signature, message)
The verifier must receive the same bytes that were signed. Trailing newlines, a different character encoding, or a JSON library that reorders keys or changes whitespace will all produce a different byte sequence. If you sign a serialized document, sign the exact string you transmit, and verify that string before parsing it.
Troubleshoot InvalidSignature
The exception means the signature did not verify against the key and bytes you supplied. It does not say which input was wrong, so check these causes in order.
The message bytes differ
This is the most common cause. Compare the bytes on both sides, not the displayed text. Print repr(message) on the signing side and the verifying side. A difference in encoding, whitespace, line endings, or serialization order is enough to fail verification.
The public key does not match the private key
Verification uses only the public key. If the verifier has a key from a different generation run, a rotated key, or a copy of the wrong file, every check will fail. Confirm the key fingerprint or the raw public key bytes before debugging the signature itself.
The signature was altered or truncated
A valid Ed25519 signature is 64 bytes. If the length is different after transmission, the signature was probably decoded or truncated incorrectly. Check base64 or hex decoding on the receiving side, and make sure the signature was not converted to text and back.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →from cryptography.exceptions import InvalidSignature
try:
public_key.verify(signature, message)
print('valid')
except InvalidSignature:
print('invalid: check message bytes, key, and signature length')
The sides use different Ed25519 variants
If one side pre-hashes the input and the other does not, the signatures will not match. See the variant section below.
Key formats for interchange
The cryptography library can serialize keys in several encodings: Raw, PEM, DER, and OpenSSH. The compatible format depends on the encoding. Raw encoding pairs with the Raw format, OpenSSH pairs with OpenSSH, and PEM and DER pair with the SubjectPublicKeyInfo structure. Mixing these produces an error or, worse, bytes that the other system misreads.
| Encoding | What it contains | Typical use | Compatibility note |
|---|---|---|---|
| Raw | The bare key bytes: 32 bytes for a public key | Protocols that define a 32-byte Ed25519 key field | Raw bytes are not PEM or DER. The receiver must expect bare bytes. |
| PEM | Base64 text with BEGIN and END lines | Configuration files and tools that read PEM containers | The cited documentation does not state which peers accept PEM for this key type. Confirm with the receiver. |
| DER | Binary ASN.1 container | Systems that read binary key containers | Same container family as PEM, without text armor. Confirm the receiver’s expected structure. |
| OpenSSH | OpenSSH public-key line format | Interchange with OpenSSH-based tooling | Use this when the other side expects an OpenSSH key line. |
Export and import a raw public key
RFC 8032 defines Ed25519 public keys as 32 bytes. Export the raw form and load it on the other side with Ed25519PublicKey.from_public_bytes():
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
raw_public = public_key.public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw,
)
assert len(raw_public) == 32
verifier = Ed25519PublicKey.from_public_bytes(raw_public)
verifier.verify(signature, message)
Export a PEM public key
pem_public = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
print(pem_public.decode('ascii'))
Keep private keys in a protected store. The format you choose for private keys is separate from the one you share. Export the private key only when your protocol requires it, and encrypt it at rest.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Ordinary Ed25519 or Ed25519ph
RFC 8032 (Internet Research Task Force, January 2017) defines two distinct signing choices. They are not interchangeable.
Best Value
| Aspect | Ordinary Ed25519 | Ed25519ph |
|---|---|---|
| Message processing | Signs the message directly under PureEdDSA | Hashes the message with SHA-512 before signing |
| Context | Empty context | Context is supported as a feature of this variant |
| Choose it when | You are building a new flow with no protocol requirement to the contrary | The protocol explicitly specifies the prehash variant |
Do not pre-hash input yourself before calling the ordinary Ed25519 API. Doing so changes the signed content, and the other side will not verify the result. Use the prehash variant only when the protocol names it and both parties agree on it.
Pre-ship checks
-
Confirm the installed
cryptographyrelease against the documentation you followed. -
Verify that the sign and verify paths use identical byte sequences, captured in the same serialization step.
Recommended: Update Every Outdated Driver on Your PC in One Scan - Free →Recommended: Fix Windows Errors and Clear Junk Files in Minutes - Free Scan →Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy. -
Check the public key and signature sizes: 32 bytes for a raw public key, 64 bytes for a signature.
-
Match key encodings to what the receiving system expects, and test one signature end to end with that system before rollout.
-
Confirm that both sides use ordinary Ed25519, or the same prehash variant, as the protocol specifies.
-
Set a private key custody and rotation process that meets your protocol’s requirements.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallSpecial offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.Quick Recap
SaleBestseller No. 1Bestseller No. 2Bestseller No. 3
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

