DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk5 min

Signing and Verifying Data with Ed25519 in Python

Sign bytes with an Ed25519PrivateKey, verify with the matching public key, and handle InvalidSignature. This guide covers exact-byte matching, key encodings, RFC 8032 sizes, and the Ed25519ph variant.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To sign and verify data with Ed25519 in Python, use the cryptography package. Call sign() on an Ed25519PrivateKey to produce a 64-byte signature, then call verify() on the matching public key with the same signature and the same bytes. A successful verify() returns None. A signature that does not match raises cryptography.exceptions.InvalidSignature.

A complete signing and verification example

The pyca/cryptography documentation for release 46.0.4 demonstrates the basic pattern. The flow has three steps:

As an Amazon Associate I earn from qualifying purchases.

  1. Generate a private key with Ed25519PrivateKey.generate().
  2. Sign the message bytes with private_key.sign(message).
  3. Derive the public key with private_key.public_key() and check the signature with public_key.verify(signature, message).
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey

private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()

message = b"invoice-1042:amount=350.00:currency=USD"
signature = private_key.sign(message)

try:
    public_key.verify(signature, message)
    print("signature valid")
except InvalidSignature:
    print("signature invalid")

The verifying side needs only the public key, the signature, and the message. The private key never leaves the signer.

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

Signing text and matching the exact bytes

The sign() and verify() methods accept bytes-like data, not Python str objects. Text must be encoded deliberately, and the same encoding must be applied on both sides:

message_text = "Order 1042 shipped"
message = message_text.encode("utf-8")
signature = private_key.sign(message)

# The verifier must reconstruct the identical byte sequence.
public_key.verify(signature, "Order 1042 shipped".encode("utf-8"))

Ed25519 signs the exact byte sequence. Re-serializing JSON, changing line endings, trimming whitespace, or decoding and re-encoding text can all change the bytes, and verification will then fail even though the data looks the same to a person.

What InvalidSignature means

Verification raises InvalidSignature when the signature does not match the public key and the message together. The exception does not say which input is wrong, so troubleshooting means checking each input against the signer.

Common causes

  • Different message bytes. The verifier received altered, re-encoded, or re-formatted data. Compare the raw bytes on both sides, for example by hashing them.
  • Wrong public key. The public key belongs to a different private key, or a key was rotated and the verifier still holds the old one.
  • Corrupted or truncated signature. A valid Ed25519 signature is 64 bytes. A signature stored as text, such as hexadecimal or base64, must be decoded back to the original 64 bytes before verification.
  • Wrong key representation. Raw key bytes were loaded where a PEM or DER container was expected, or the reverse. See the serialization section below.

Treat InvalidSignature as a reject decision. Do not catch it and continue processing the data.

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

Key and signature sizes

RFC 8032, published by the Internet Research Task Force in January 2017, specifies Ed25519 public keys as 32 bytes and signatures as 64 bytes. These are format sizes from the specification, not performance measurements. A length check is a useful sanity test before handing bytes to the library, because a wrong length usually points to an encoding or decoding error.

Serializing keys for other systems

The library can write and read private and public keys in several encodings. The encoding and the format must be chosen together, because each encoding pairs with a specific format:

Encoding Public-key format it pairs with What to expect
Raw Raw Bare 32-byte key with no header or container
PEM SubjectPublicKeyInfo Base64 text between BEGIN and END lines
DER SubjectPublicKeyInfo Binary ASN.1 structure with the same content as PEM
OpenSSH OpenSSH Single-line ssh-ed25519 public key text

Raw key bytes and PEM or DER containers are not interchangeable wire formats. The receiving system dictates which one to use, and the peer’s accepted format must be confirmed before a key is exported. Whether a particular peer or backend accepts each form is not stated by the library documentation and must be checked against that system.

Raw public keys

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

loaded_public_key = Ed25519PublicKey.from_public_bytes(raw_public)
loaded_public_key.verify(signature, message)

PEM public and private keys

pem_public = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

pem_private = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption(),
)

NoEncryption() writes the private key in plaintext. Use it only when the file is protected by other means, such as restricted file permissions or a secrets manager. For stored keys, pass serialization.BestAvailableEncryption(passphrase) with a passphrase obtained from a secret store, and load the key later with serialization.load_pem_private_key(pem_private, password=passphrase).

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

Ed25519 or Ed25519ph

RFC 8032 defines two signature choices that are easy to confuse. Plain Ed25519 is the PureEdDSA variant: it signs the message directly. Ed25519ph is a prehash variant: it hashes the message with SHA-512 before signing. The two produce different signatures for the same input, so a verifier using one variant cannot accept signatures made with the other.

Variant Message processing Context
Ed25519 Signs the message directly (PureEdDSA) Empty context
Ed25519ph Hashes the message with SHA-512, then signs the hash Context is a feature of the distinct variants, not of plain Ed25519

Do not pre-hash input before calling the ordinary Ed25519 API. Use the prehash variant only when the protocol specifies it and both parties agree on it. Confirm that the library you plan to use exposes the variant you need; the Ed25519 API documented for release 46.0.4 covers the ordinary variant.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Handling keys and choosing this primitive

The pyca/cryptography documentation describes the Ed25519 API as a hazardous-materials interface. That label means the primitive is low-level and security-sensitive: it is not a substitute for a higher-level protocol design. Application code should use an established library, not a hand-written curve implementation.

The library documentation states: “If you do not have legacy interoperability concerns then you should strongly consider using this signature algorithm.” If your peers require older algorithms, follow their requirements. Otherwise Ed25519 is a strong default for new signing flows.

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

Key custody and rotation are not handled by the signing code. Store private keys in a protected location, limit who can read them, and follow the rotation schedule your protocol requires. The verifying side must also know which public key is current, so rotation needs a plan for updating every verifier.

Checklist before shipping a signature flow

  • Confirm the installed version with pip show cryptography and check the matching documentation. The sizes and API details here reflect release 46.0.4; the main-branch documentation is not pinned to a release.
  • Define the exact byte sequence that is signed, including encoding and any serialization step.
  • Match the key encoding and format to the receiving system, and test the round trip with that system.
  • Decide which Ed25519 variant the protocol uses before writing any code.
  • Reject on InvalidSignature and log the failure without logging private key material.
  • Store private keys with restricted access and document the rotation process for public keys.

This guidance is based on pyca/cryptography 46.0.4 documentation and RFC 8032 (January 2017). It does not cover a specific deployment’s key-management controls or the backend support of every build, so verify those in your own environment.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

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

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.