Table of Contents

Ed25519 Class

Definition

Namespace
Bodu.Security.Cryptography
Assembly
Bodu.Security.Cryptography.dll
Package
Bodu.Security.Cryptography 1.2.0
Source
Ed25519.KeyFormats.cs

Provides a managed implementation of the Ed25519 digital signature algorithm (PureEdDSA over edwards25519) as defined in RFC 8032, exposed through the standard AsymmetricAlgorithm framework. This class cannot be inherited.

public sealed class Ed25519 : RawKeyAsymmetricAlgorithm, IDisposable
Inheritance
Ed25519
Implements
Inherited Members
Extension Methods

Examples

using var signer = Ed25519.Create();
signer.GenerateKey();
byte[] signature = signer.SignData(message);

using var verifier = Ed25519.Create();
verifier.ImportPublicKey(signer.ExportPublicKey());
bool valid = verifier.VerifyData(message, signature);

Remarks

Ed25519 produces deterministic 64-byte signatures from a 32-byte private seed at a 128-bit security level. The same message signed twice under the same key yields the identical signature; no signing nonce is consumed, which removes the catastrophic nonce-reuse failure mode of ECDSA-style schemes.

Parameters at a glance.

  • Private key: 32-byte seed (RFC 8032 §5.1.5); public key: 32 bytes; signature: 64 bytes (R ‖ S).
  • Hash: SHA-512; security level: 128 bits; specification: RFC 8032 (Ed25519, "pure" variant).

Scope. Only pure Ed25519 is implemented. The pre-hash (Ed25519ph) and context (Ed25519ctx) variants of RFC 8032 are deliberately out of scope for this version. The raw RFC 8032 32-byte key encodings, the RFC 8410 PKCS#8 / SubjectPublicKeyInfo DER containers (OID 1.3.101.112), and the RFC 7468 PEM helpers inherited from AsymmetricAlgorithm (ImportFromPem, ExportPkcs8PrivateKeyPem, ExportSubjectPublicKeyInfoPem) are all supported; the XML members and encrypted PKCS#8 are out of scope and throw NotSupportedException.

Verification policy. VerifyData(ReadOnlySpan<byte>, ReadOnlySpan<byte>) applies the cofactorless equation [S]B = R + [k]A and rejects signatures whose S component is at or above the group order (the RFC 8032 malleability check) and points whose encodings are non-canonical. Malformed or wrong-length signatures return false rather than throwing.

Signing runs in constant time with respect to the private key, and intermediate secrets (the expanded SHA-512 seed, the per-signature scalar r) are zeroed before returning. Private key material is zeroed when the instance is disposed. This implementation offers best-effort side-channel resistance and has not been independently audited.

Constructors

Ed25519()

Initializes a new instance of the Ed25519 class with no key material.

public Ed25519()

Remarks

Call GenerateKey() to create a fresh key pair, or import existing material with ImportPrivateKey(ReadOnlySpan<byte>) or ImportPublicKey(ReadOnlySpan<byte>) before signing or verifying.

Fields

PrivateKeySizeInBytes

The size, in bytes, of an Ed25519 private key seed.

public const int PrivateKeySizeInBytes = 32

Field Value

int

PublicKeySizeInBytes

The size, in bytes, of an Ed25519 public key.

public const int PublicKeySizeInBytes = 32

Field Value

int

SignatureSizeInBytes

The size, in bytes, of an Ed25519 signature.

public const int SignatureSizeInBytes = 64

Field Value

int

Properties

AlgorithmName

Gets the algorithm name "Ed25519".

public string AlgorithmName { get; }

Property Value

string

The constant string "Ed25519".

HasPrivateKey

Gets a value indicating whether the instance currently holds a private key.

public bool HasPrivateKey { get; }

Property Value

bool

true when private key material is present; otherwise, false.

Exceptions

ObjectDisposedException

The instance has been disposed.

HasPublicKey

Gets a value indicating whether the instance currently holds a public key.

public bool HasPublicKey { get; }

Property Value

bool

true when public key material is present; otherwise, false.

Exceptions

ObjectDisposedException

The instance has been disposed.

KeyExchangeAlgorithm

When overridden in a derived class, gets the name of the key exchange algorithm. Otherwise, throws an NotImplementedException.

public override string? KeyExchangeAlgorithm { get; }

Property Value

string

The name of the key exchange algorithm.

SecurityStrengthBits

Gets the approximate classical security strength of Ed25519, in bits.

public int SecurityStrengthBits { get; }

Property Value

int

The value 128.

SignatureAlgorithm

When implemented in a derived class, gets the name of the signature algorithm. Otherwise, always throws a NotImplementedException.

public override string? SignatureAlgorithm { get; }

Property Value

string

The name of the signature algorithm.

Methods

Create()

Creates a new Ed25519 instance with no key material.

public static Ed25519 Create()

Returns

Ed25519

A new Ed25519 instance.

ExportPrivateKey()

Exports the raw 32-byte RFC 8032 private key seed.

public byte[] ExportPrivateKey()

Returns

byte[]

A fresh copy of the 32-byte seed exactly as generated or imported.

Exceptions

ObjectDisposedException

The instance has been disposed.

CryptographicException

The instance does not hold a private key.

ExportPublicKey()

Exports the raw 32-byte RFC 8032 public key.

public byte[] ExportPublicKey()

Returns

byte[]

A fresh copy of the 32-byte compressed point encoding.

Exceptions

ObjectDisposedException

The instance has been disposed.

CryptographicException

The instance does not hold a public key.

FromXmlString(string)

When overridden in a derived class, reconstructs an AsymmetricAlgorithm object from an XML string. Otherwise, throws a NotImplementedException.

public override void FromXmlString(string xmlString)

Parameters

xmlString string

The XML string to use to reconstruct the AsymmetricAlgorithm object.

GenerateKey()

Generates a fresh random key pair, replacing any existing key material on the instance.

public void GenerateKey()

Remarks

The 32-byte seed is drawn from a cryptographically secure random source. Any previously held private key is zeroed before being replaced.

Exceptions

ObjectDisposedException

The instance has been disposed.

ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte>, ReadOnlySpan<byte>, out int)

When overridden in a derived class, imports the public/private keypair from a PKCS#8 EncryptedPrivateKeyInfo structure after decrypting with a byte-based password, replacing the keys for this object.

public override void ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source, out int bytesRead)

Parameters

passwordBytes ReadOnlySpan<byte>

The bytes to use as a password when decrypting the key material.

source ReadOnlySpan<byte>

The bytes of a PKCS#8 EncryptedPrivateKeyInfo structure in the ASN.1-BER encoding.

bytesRead int

When this method returns, contains a value that indicates the number of bytes read from source. This parameter is treated as uninitialized.

Exceptions

CryptographicException

The password is incorrect.

-or-

The contents of source indicate the Key Derivation Function (KDF) to apply is the legacy PKCS#12 KDF, which requires char-based passwords.

-or-

The contents of source do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.

-or-

The contents of source indicate the key is for an algorithm other than the algorithm represented by this instance.

-or-

The contents of source represent the key in a format that is not supported.

-or-

The algorithm-specific key import failed.

NotImplementedException

A derived type has not overriden this member.

ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char>, ReadOnlySpan<byte>, out int)

When overridden in a derived class, imports the public/private keypair from a PKCS#8 EncryptedPrivateKeyInfo structure after decrypting with a char-based password, replacing the keys for this object.

public override void ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source, out int bytesRead)

Parameters

password ReadOnlySpan<char>

The password to use for decrypting the key material.

source ReadOnlySpan<byte>

The bytes of a PKCS#8 EncryptedPrivateKeyInfo structure in the ASN.1-BER encoding.

bytesRead int

When this method returns, contains a value that indicates the number of bytes read from source. This parameter is treated as uninitialized.

Exceptions

CryptographicException

The password is incorrect.

-or-

The contents of source do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.

-or-

The contents of source indicate the key is for an algorithm other than the algorithm represented by this instance.

-or-

The contents of source represent the key in a format that is not supported.

-or-

The algorithm-specific key import failed.

NotImplementedException

A derived type has not overriden this member.

ImportPkcs8PrivateKey(ReadOnlySpan<byte>, out int)

When overriden in a derived class, imports the public/private keypair from a PKCS#8 PrivateKeyInfo structure after decryption, replacing the keys for this object.

public override void ImportPkcs8PrivateKey(ReadOnlySpan<byte> source, out int bytesRead)

Parameters

source ReadOnlySpan<byte>

The bytes of a PKCS#8 PrivateKeyInfo structure in the ASN.1-BER encoding.

bytesRead int

When this method returns, contains a value that indicates the number of bytes read from source. This parameter is treated as uninitialized.

Exceptions

CryptographicException

The contents of source do not represent an ASN.1-BER-encoded PKCS#8 PrivateKeyInfo structure.

-or-

The contents of source indicate the key is for an algorithm other than the algorithm represented by this instance.

-or-

The contents of source represent the key in a format that is not supported.

-or-

The algorithm-specific key import failed.

NotImplementedException

A derived type has not overriden this member.

ImportPrivateKey(ReadOnlySpan<byte>)

Imports a raw 32-byte RFC 8032 private key seed and derives the matching public key, replacing any existing key material on the instance.

public void ImportPrivateKey(ReadOnlySpan<byte> privateKey)

Parameters

privateKey ReadOnlySpan<byte>

The 32-byte private seed to import. The caller's buffer is copied and never modified.

Exceptions

ObjectDisposedException

The instance has been disposed.

ArgumentException

privateKey is not exactly 32 bytes long.

ImportPublicKey(ReadOnlySpan<byte>)

Imports a raw 32-byte RFC 8032 public key, replacing any existing key material on the instance.

public void ImportPublicKey(ReadOnlySpan<byte> publicKey)

Parameters

publicKey ReadOnlySpan<byte>

The 32-byte compressed point encoding to import.

Remarks

The encoding is validated by fully decompressing the point; non-canonical y values and encodings without a square x² candidate are rejected, as are small-order points, which lie outside the prime-order subgroup and are incompatible with Bodu's strict cofactorless verification policy (see VerifyData(ReadOnlySpan<byte>, ReadOnlySpan<byte>)). Any private key previously held by the instance is zeroed and discarded, leaving a verify-only instance.

Exceptions

ObjectDisposedException

The instance has been disposed.

ArgumentException

publicKey is not exactly 32 bytes long, or is not a canonical encoding of a point on edwards25519.

ImportSubjectPublicKeyInfo(ReadOnlySpan<byte>, out int)

When overriden in a derived class, imports the public key from an X.509 SubjectPublicKeyInfo structure after decryption, replacing the keys for this object.

public override void ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source, out int bytesRead)

Parameters

source ReadOnlySpan<byte>

The bytes of an X.509 SubjectPublicKeyInfo structure in the ASN.1-DER encoding.

bytesRead int

When this method returns, contains a value that indicates the number of bytes read from source. This parameter is treated as uninitialized.

Exceptions

CryptographicException

The contents of source do not represent an ASN.1-DER-encoded X.509 SubjectPublicKeyInfo structure.

-or-

The contents of source indicate the key is for an algorithm other than the algorithm represented by this instance.

-or-

The contents of source represent the key in a format that is not supported.

-or-

The algorithm-specific key import failed.

NotImplementedException

A derived type has not overriden this member.

SignData(ReadOnlySpan<byte>)

Signs the supplied data with the instance's private key, producing the deterministic 64-byte Ed25519 signature.

public byte[] SignData(ReadOnlySpan<byte> data)

Parameters

data ReadOnlySpan<byte>

The message bytes to sign. May be empty.

Returns

byte[]

The 64-byte signature R ‖ S.

Exceptions

ObjectDisposedException

The instance has been disposed.

CryptographicException

The instance does not hold a private key.

SignData(ReadOnlySpan<byte>, Span<byte>)

Signs the supplied data with the instance's private key, writing the deterministic 64-byte Ed25519 signature into destination.

public void SignData(ReadOnlySpan<byte> data, Span<byte> destination)

Parameters

data ReadOnlySpan<byte>

The message bytes to sign. May be empty.

destination Span<byte>

The 64-byte span that receives the signature R ‖ S.

Exceptions

ObjectDisposedException

The instance has been disposed.

ArgumentException

destination is not exactly 64 bytes long.

CryptographicException

The instance does not hold a private key.

ToXmlString(bool)

When overridden in a derived class, creates and returns an XML string representation of the current AsymmetricAlgorithm object. Otherwise, throws a NotImplementedException.

public override string ToXmlString(bool includePrivateParameters)

Parameters

includePrivateParameters bool

true to include private parameters; otherwise, false.

Returns

string

An XML string encoding of the current AsymmetricAlgorithm object.

TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte>, PbeParameters, Span<byte>, out int)

When overridden in a derived class, attempts to export the current key in the PKCS#8 EncryptedPrivateKeyInfo format into a provided buffer, using a byte-based password.

public override bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten)

Parameters

passwordBytes ReadOnlySpan<byte>

The bytes to use as a password when encrypting the key material.

pbeParameters PbeParameters

The password-based encryption (PBE) parameters to use when encrypting the key material.

destination Span<byte>

The byte span to receive the PKCS#8 EncryptedPrivateKeyInfo data.

bytesWritten int

When this method returns, contains a value that indicates the number of bytes written to destination. This parameter is treated as uninitialized.

Returns

bool

true if destination is big enough to receive the output; otherwise, false.

Exceptions

CryptographicException

The key could not be exported.

-or-

pbeParameters indicates that TripleDes3KeyPkcs12 should be used, which requires char-based passwords.

NotImplementedException

A derived type has not overriden this member.

TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char>, PbeParameters, Span<byte>, out int)

When overriden in a derived class, attempts to export the current key in the PKCS#8 EncryptedPrivateKeyInfo format into a provided buffer, using a char-based password.

public override bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten)

Parameters

password ReadOnlySpan<char>

The password to use when encrypting the key material.

pbeParameters PbeParameters

The password-based encryption (PBE) parameters to use when encrypting the key material.

destination Span<byte>

The byte span to receive the PKCS#8 EncryptedPrivateKeyInfo data.

bytesWritten int

When this method returns, contains a value that indicates the number of bytes written to destination. This parameter is treated as uninitialized.

Returns

bool

true if destination is big enough to receive the output; otherwise, false.

Exceptions

CryptographicException

The key could not be exported.

NotImplementedException

A derived type has not overriden this member.

TryExportPkcs8PrivateKey(Span<byte>, out int)

When overridden in a derived class, attempts to export the current key in the PKCS#8 PrivateKeyInfo format into a provided buffer.

public override bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten)

Parameters

destination Span<byte>

The byte span to receive the PKCS#8 PrivateKeyInfo data.

bytesWritten int

When this method returns, contains a value that indicates the number of bytes written to destination. This parameter is treated as uninitialized.

Returns

bool

true if destination is big enough to receive the output; otherwise, false.

Exceptions

CryptographicException

The key could not be exported.

NotImplementedException

A derived type has not overriden this member.

TryExportSubjectPublicKeyInfo(Span<byte>, out int)

When overridden in a derived class, attempts to export the current key in the X.509 SubjectPublicKeyInfo format into a provided buffer.

public override bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten)

Parameters

destination Span<byte>

The byte span to receive the X.509 SubjectPublicKeyInfo data.

bytesWritten int

When this method returns, contains a value that indicates the number of bytes written to destination. This parameter is treated as uninitialized.

Returns

bool

true if destination is big enough to receive the output; otherwise, false.

Exceptions

CryptographicException

The key could not be exported.

NotImplementedException

A derived type has not overriden this member.

VerifyData(ReadOnlySpan<byte>, ReadOnlySpan<byte>)

Verifies an Ed25519 signature over the supplied data against the instance's public key.

public bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature)

Parameters

data ReadOnlySpan<byte>

The message bytes that were signed. May be empty.

signature ReadOnlySpan<byte>

The candidate 64-byte signature R ‖ S.

Returns

bool

true when the signature is valid; false for any invalid, malformed, non-canonical, or wrong-length signature.

Remarks

Verification never throws for bad signature input: every failure mode - wrong length, S ≥ L, a non-canonical or off-curve R, or a small-order R or public key - yields false. Verification time may vary with the inputs, which is acceptable because all inputs to verification are public.

This is a deliberately strict policy. Bodu checks the cofactorless equation [S]B = R + [k]A rather than the cofactored [8][S]B = [8]R + [8][k]A of RFC 8032 §5.1.7, and additionally rejects small-order R and public keys. The accepted-signature set is therefore a strict subset of RFC 8032 cofactored verification: every signature Bodu accepts is also accepted by a cofactored verifier, but a cofactored verifier may accept edge-case signatures (those differing by a torsion component) that Bodu rejects. Callers requiring exact consensus with a specific cofactored or ZIP-215 verifier must account for this difference.

Exceptions

ObjectDisposedException

The instance has been disposed.

CryptographicException

The instance does not hold a public key.

Applies to

ProductVersions
.NET8, 10