Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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

  1. Install the package with pip install cryptography. Confirm the release you actually have with pip 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.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  2. Save this as sign_demo.py and run it with python sign_demo.py:

    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

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Ordinary Ed25519 or Ed25519ph

RFC 8032 (Internet Research Task Force, January 2017) defines two distinct signing choices. They are not interchangeable.

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

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.