Keyboard Shortcuts N Next post
P Previous post
S Save / unsave
R Read aloud
T Toggle theme
/ Focus search
Esc Close panels
🔥
Ready to read...
Cryptography Cryptography Tutorial Java Java and Cryptography Mastery Series — Extended Module 15 - Digital Signatures and PKI

Java Program for EdDSA Edwards Curve Digital Signature

Reviewed & accurate
AI Summary

Introduction

The eddsa signature java tutorial covers the Edwards-curve Digital Signature Algorithm, which was designed by Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, and Bo-Yin Yang and published in 2012. EdDSA with the Ed25519 curve was standardized by the IETF as RFC 8032 in January 2017 and added to the JDK in Java 15 (JEP 369, September 2020). EdDSA is the modern alternative to ECDSA: it offers deterministic signatures, side-channel resistance, and faster signing and verification for equivalent security.

For a Java learner the eddsa signature java example below matters because the JDK ships the KeyPairGenerator and Signature classes for EdDSA in the SunEC provider. The standard API (KeyPairGenerator.getInstance("Ed25519").generateKeyPair() and Signature.getInstance("Ed25519")) is the production way to use EdDSA in Java. Ed25519 is also the default signature algorithm in OpenSSH 8.0 and later, in WireGuard VPN, and in the Signal protocol.

EdDSA's deterministic signatures are the headline feature. Unlike ECDSA, which requires a fresh random nonce per signature (and reveals the private key if the nonce is reused), EdDSA derives the nonce from the private key and the message hash using SHA-512. The derivation is deterministic, which means the same private key and the same message always produce the same signature, and there is no random-number requirement.

What is EdDSA Signature (Edwards Curve Digital Signature)?

eddsa signature java is an asymmetric cryptographic signature scheme. EdDSA uses an Edwards-form elliptic curve over a finite field, a base point B of order L, a per-key private key s (a scalar), and a public key A = s times B. The signature on a message m is a pair (R, S), where R is a curve point and S is a scalar. The signature size is 64 bytes for Ed25519 (32 bytes for R and 32 bytes for S).

The signature scheme belongs to the family of discrete-log-based signature schemes, alongside ElGamal (1985), Schnorr (1989), DSA (1991), and ECDSA (1998). EdDSA is the Edwards-curve variant of Schnorr signatures; the underlying mathematics is the same as Schnorr, but the group is the points on an Edwards-form curve (specifically, the twisted Edwards curve -x squared + y squared = 1 plus d times x squared times y squared for Ed25519).

The hard problem is the elliptic-curve discrete logarithm problem, same as ECDSA. The best-known algorithm for the elliptic-curve discrete logarithm is Pollard's rho, which has square-root complexity in the group order L. Ed25519 has a 253-bit group order, which gives about 126 bits of security, which is equivalent to a 2048-bit RSA key or a 256-bit symmetric key (with some margin lost).

The Ed25519 curve was designed to be safer than the NIST curves. The curve parameters are transparent (the curve equation is fully specified by the prime field and the d coefficient), the base point is the standard base point, and the group order is the standard group order. The cofactor is 8, which is handled by the signing and verification algorithms.

How EdDSA Works Step by Step

Step 1: Key generation. The signer generates a random 32-byte private key s. The signer hashes s with SHA-512 to get a 64-byte output, clamps the first 32 bytes (sets the three low bits to zero, sets bit 254 to one, clears bit 255) to get the scalar a, and uses the second 32 bytes as the prefix for nonce derivation. The public key is A = a times B, encoded as the Y coordinate of A plus the sign of X (32 bytes).

Step 2: Signing. The signer computes r = SHA-512(nonce-prefix || message) modulo L, computes R = r times B, computes h = SHA-512(R || A || message) modulo L, and computes S = (r + h times a) modulo L. The signature is (R, S), encoded as 32 bytes for R plus 32 bytes for S (64 bytes total).

Step 3: Verification. The verifier computes h = SHA-512(R || A || message) modulo L, computes the point S times B, and the point h times A, and the signature is valid if and only if S times B equals R plus h times A (using the standard Edwards-curve point addition). The verification is one scalar multiplication, one point multiplication, one point addition, and one comparison.

Step 4: Deterministic property. The nonce r is derived from the nonce-prefix (part of the private key) and the message, both hashed with SHA-512. The derivation is deterministic, which means the same private key and the same message always produce the same signature. There is no random-number requirement, which eliminates the Sony PlayStation 3 hack class of bugs.

Step 5: Side-channel resistance. The Edwards-curve point addition is complete (works for all input pairs without special cases), which makes the implementation side-channel resistant when combined with the deterministic nonce. The clamping of the scalar (clearing the three low bits, setting bit 254, clearing bit 255) prevents certain small-subgroup attacks.

Step 6: Batch verification. EdDSA supports batch verification, which verifies multiple signatures faster than verifying them individually. The verifier combines multiple signatures into a single equation that holds if and only if all the individual signatures are valid (with high probability). Batch verification is used in blockchain systems to verify blocks of transactions.

Java Program for EdDSA Edwards Curve Digital Signature


import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SecureRandom;
import java.security.spec.EdECParameterSpec;
import java.security.interfaces.EdECPrivateKey;
import java.security.interfaces.EdECPublicKey;
import java.util.Arrays;
import java.util.Base64;

public class EdDsaDemo {

    public static void main(String[] args) throws Exception {
        // Generate an Ed25519 key pair.
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
        KeyPair keys = kpg.generateKeyPair();

        EdECPrivateKey priv = (EdECPrivateKey) keys.getPrivate();
        EdECPublicKey pub = (EdECPublicKey) keys.getPublic();
        System.out.println("=== Ed25519 key pair ===");
        System.out.println("Algorithm          : " + priv.getAlgorithm());
        System.out.println("Private key bytes  : " + priv.getBytes().length);
        System.out.println("Public key point   : " + pub.getPoint());
        System.out.println("Public key bytes   : " + pub.getEncoded().length);

        // Sign with Ed25519.
        byte[] message = "EdDSA is deterministic and side-channel resistant.".getBytes("UTF-8");
        Signature eddsa = Signature.getInstance("Ed25519");
        eddsa.initSign(priv);
        eddsa.update(message);
        byte[] signature = eddsa.sign();

        // Verify.
        eddsa.initVerify(pub);
        eddsa.update(message);
        boolean ok = eddsa.verify(signature);

        // Tamper detection.
        byte[] tampered = message.clone();
        tampered[3] ^= 0x01;
        eddsa.initVerify(pub);
        eddsa.update(tampered);
        boolean tamperDetected = !eddsa.verify(signature);

        // Two EdDSA signatures of the same message are byte-identical (deterministic).
        eddsa.initSign(priv);
        eddsa.update(message);
        byte[] sig2 = eddsa.sign();
        boolean sigsIdentical = Arrays.equals(signature, sig2);

        System.out.println();
        System.out.println("=== Signature ===");
        System.out.println("Message            : " + new String(message, "UTF-8"));
        System.out.println("Signature (b64)    : " + Base64.getEncoder().encodeToString(signature).substring(0, 40) + "...");
        System.out.println("Signature length   : " + signature.length + " bytes (raw, no DER)");
        System.out.println("Verify ok          : " + ok);
        System.out.println("Tamper detected    : " + tamperDetected);
        System.out.println("Sigs identical     : " + sigsIdentical);

        // Demonstrate Ed448 if available (Java 15+).
        try {
            KeyPairGenerator kpg448 = KeyPairGenerator.getInstance("Ed448");
            KeyPair keys448 = kpg448.generateKeyPair();
            Signature ed448 = Signature.getInstance("Ed448");
            ed448.initSign(keys448.getPrivate());
            ed448.update(message);
            byte[] sig448 = ed448.sign();
            System.out.println();
            System.out.println("=== Ed448 signature ===");
            System.out.println("Signature length   : " + sig448.length + " bytes (raw, no DER)");
            System.out.println("Security level     : ~224 bits (vs ~126 bits for Ed25519)");
        } catch (Exception e) {
            System.out.println("Ed448 not available on this JVM: " + e.getMessage());
        }
    }
}

Code Explanation Line by Line

The class EdDsaDemo uses the JDK KeyPairGenerator for Ed25519 to produce an EdDSA key pair. The KeyPairGenerator uses the algorithm name "Ed25519", which is the standard name in the SunEC provider. The EdECPrivateKey interface exposes the 32-byte private key as a byte array; the EdECPublicKey interface exposes the public key as a point (which is the Y coordinate plus the sign of X, encoded in 32 bytes).

The JDK-standard signature uses the Signature class with the algorithm name "Ed25519". Unlike ECDSA, the EdDSA signature is not DER-encoded; the signature is the raw 64-byte (R, S) pair. The raw encoding makes EdDSA signatures smaller and easier to handle than DER-encoded ECDSA signatures.

The verification succeeds for the original message and fails for the tampered message, which is the integrity guarantee of digital signatures. The two-signature test signs the same message twice and confirms the two signatures are byte-identical, which is the deterministic property. This is the headline feature of EdDSA over ECDSA: deterministic signatures eliminate the random-number requirement and the risk of nonce reuse.

The Ed448 demonstration shows the other EdDSA variant standardized in RFC 8032. Ed448 uses the Edwards 448 curve (also called Goldilocks), which provides about 224 bits of security versus the 126 bits of Ed25519. Ed448 is supported in the SunEC provider since Java 15 (the same JEP that added EdDSA in general). The Ed448 signature is 114 bytes (57 bytes for R and 57 bytes for S).

The SunEC provider implements the standard EdDSA algorithm from RFC 8032. The implementation uses the constant-time point arithmetic that EdDSA was designed for, which makes the implementation side-channel resistant. The KeyPairGenerator and Signature classes are the production way to use EdDSA in Java.

Sample Input and Output

=== Ed25519 key pair ===
Algorithm          : Ed25519
Private key bytes  : 32
Public key point   : java.security.spec.EdECPoint@...
Public key bytes   : 91

=== Signature ===
Message            : EdDSA is deterministic and side-channel resistant.
Signature (b64)    : 6m4...base64-prefix-here...
Signature length   : 64 bytes (raw, no DER)
Verify ok          : true
Tamper detected    : true
Sigs identical     : true

=== Ed448 signature ===
Signature length   : 114 bytes (raw, no DER)
Security level     : ~224 bits (vs ~126 bits for Ed25519)

The Ed25519 key pair uses a 32-byte private key and a 32-byte public key (encoded as 91 bytes in the X.509 SubjectPublicKeyInfo format). The signature is 64 bytes raw, which is much smaller than the DER-encoded ECDSA signature (71 bytes) or the RSA signature (256 bytes). The verification succeeds for the original message and fails for the tampered message. The two signatures of the same message are byte-identical, confirming the deterministic property. The Ed448 signature is 114 bytes.

Common Mistakes to Avoid

The first mistake is assuming EdDSA signatures are non-deterministic. EdDSA is deterministic, which means the same private key and the same message always produce the same signature. This is a feature, not a bug: the determinism eliminates the random-number requirement and the risk of nonce reuse. Do not try to add randomness to EdDSA; the design is deterministic on purpose.

The second mistake is using EdDSA for encryption. EdDSA is a signature scheme, not an encryption scheme. For encryption, use the X25519 key exchange (the elliptic-curve Diffie-Hellman variant of Curve25519) to derive a symmetric key, then use AES-GCM or ChaCha20-Poly1305 for the encryption. The X25519 key exchange is standardized in RFC 7748 and supported in the SunEC provider since Java 11.

The third mistake is using the wrong curve. Ed25519 is the most widely deployed EdDSA curve; Ed448 is larger and slower but provides higher security. For new designs, Ed25519 is the default recommendation; Ed448 is for users who want the extra security margin and can tolerate the slower performance.

The fourth mistake is using EdDSA with a Java version earlier than 15. EdDSA was added to the JDK in Java 15 (JEP 369). On earlier Java versions, you need to use the BouncyCastle provider (which has supported EdDSA since version 1.58) or the Nettyty library. The standard KeyPairGenerator and Signature classes for EdDSA are not available before Java 15.

Real-World Applications

EdDSA is the default signature algorithm in OpenSSH 8.0 and later, where the ssh-ed25519 algorithm is preferred over ssh-rsa (RSA with SHA-1, deprecated) and rsa-sha2-256 (RSA with SHA-2). The Ed25519 key is 32 bytes (versus 256 bytes for RSA-2048), the signature is 64 bytes (versus 256 bytes for RSA-2048), and the signing and verification are both faster than RSA for equivalent security. OpenSSH generates Ed25519 keys by default since version 8.0.

WireGuard VPN uses Ed25519 (actually Curve25519 for key exchange and Ed25519 for the handshake signature) as the only signature algorithm. WireGuard was designed to be minimal: one key exchange, one signature algorithm, one symmetric cipher (ChaCha20-Poly1305). The minimalism makes the WireGuard implementation much smaller and easier to audit than OpenVPN or IPsec.

The Signal protocol uses Ed25519 for the identity keys of users. The Signal protocol is the basis of the messaging in WhatsApp, Facebook Messenger (in secret conversations), and Google Messages (in RCS end-to-end encrypted chats). Ed25519 was chosen because of its determinism (which prevents nonce-reuse bugs) and its side-channel resistance (which is important on mobile devices with various attack surfaces).

The Minisign and OpenBSD signify tools use Ed25519 for the signature of the software distribution files. The FreeBSD pkg tool and the OpenBSD package manager both verify Ed25519 signatures on the package metadata. The use of Ed25519 in package management is driven by the small signature size (64 bytes) and the fast verification (much faster than RSA for equivalent security).

The age encryption tool (moderncryptographics.com/age, designed by Filippo Valsorda) uses X25519 for the key exchange and Ed25519 for the SSH key compatibility (the SSH key can be used as an age recipient). The age tool is the modern replacement for GPG for file encryption; the use of Curve25519 in both X25519 and Ed25519 makes the implementation small and consistent.

The eddsa signature java tutorial in this post shows the JDK-standard KeyPairGenerator and Signature classes for Ed25519 and Ed448. For new designs that need asymmetric signatures, Ed25519 is the modern recommendation: it offers deterministic signatures, side-channel resistance, fast signing and verification, and small keys and signatures. The companion tutorials cover DSA, ECDSA, and RSA signatures for legacy compatibility.

Conclusion

In this eddsa signature java tutorial we built the EdDSA signature scheme using the JDK Signature class with Ed25519 and Ed448, demonstrated the deterministic property, and explained why EdDSA is the modern recommendation for new designs that need asymmetric signatures. EdDSA is the default signature algorithm in OpenSSH, WireGuard, and the Signal protocol; for new designs, use Ed25519. Next, study the ECDSA tutorial, the DSA tutorial, the RSA signature tutorial, and the X25519 key exchange that pairs with Ed25519 for end-to-end encryption.

Test Your Knowledge
How did you find this?

Comments

Join the discussion! Sign in with your Google or Blogger account, or comment as Anonymous - no account needed. For quick questions, also reach me on Telegram @cytestch.

Comments