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
PublicKeySizeInBytes
The size, in bytes, of an Ed25519 public key.
public const int PublicKeySizeInBytes = 32
Field Value
SignatureSizeInBytes
The size, in bytes, of an Ed25519 signature.
public const int SignatureSizeInBytes = 64
Field Value
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
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
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
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
xmlStringstringThe 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
passwordBytesReadOnlySpan<byte>The bytes to use as a password when decrypting the key material.
sourceReadOnlySpan<byte>The bytes of a PKCS#8 EncryptedPrivateKeyInfo structure in the ASN.1-BER encoding.
bytesReadintWhen 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
sourceindicate the Key Derivation Function (KDF) to apply is the legacy PKCS#12 KDF, which requires char-based passwords.-or-
The contents of
sourcedo not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.-or-
The contents of
sourceindicate the key is for an algorithm other than the algorithm represented by this instance.-or-
The contents of
sourcerepresent 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
passwordReadOnlySpan<char>The password to use for decrypting the key material.
sourceReadOnlySpan<byte>The bytes of a PKCS#8 EncryptedPrivateKeyInfo structure in the ASN.1-BER encoding.
bytesReadintWhen 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
sourcedo not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.-or-
The contents of
sourceindicate the key is for an algorithm other than the algorithm represented by this instance.-or-
The contents of
sourcerepresent 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
sourceReadOnlySpan<byte>The bytes of a PKCS#8 PrivateKeyInfo structure in the ASN.1-BER encoding.
bytesReadintWhen 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
sourcedo not represent an ASN.1-BER-encoded PKCS#8 PrivateKeyInfo structure.-or-
The contents of
sourceindicate the key is for an algorithm other than the algorithm represented by this instance.-or-
The contents of
sourcerepresent 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
privateKeyReadOnlySpan<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
privateKeyis 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
publicKeyReadOnlySpan<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
publicKeyis 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
sourceReadOnlySpan<byte>The bytes of an X.509 SubjectPublicKeyInfo structure in the ASN.1-DER encoding.
bytesReadintWhen 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
sourcedo not represent an ASN.1-DER-encoded X.509 SubjectPublicKeyInfo structure.-or-
The contents of
sourceindicate the key is for an algorithm other than the algorithm represented by this instance.-or-
The contents of
sourcerepresent 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
dataReadOnlySpan<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
dataReadOnlySpan<byte>The message bytes to sign. May be empty.
destinationSpan<byte>The 64-byte span that receives the signature R ‖ S.
Exceptions
- ObjectDisposedException
The instance has been disposed.
- ArgumentException
destinationis 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
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
passwordBytesReadOnlySpan<byte>The bytes to use as a password when encrypting the key material.
pbeParametersPbeParametersThe password-based encryption (PBE) parameters to use when encrypting the key material.
destinationSpan<byte>The byte span to receive the PKCS#8 EncryptedPrivateKeyInfo data.
bytesWrittenintWhen this method returns, contains a value that indicates the number of bytes written to
destination. This parameter is treated as uninitialized.
Returns
Exceptions
- CryptographicException
The key could not be exported.
-or-
pbeParametersindicates 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
passwordReadOnlySpan<char>The password to use when encrypting the key material.
pbeParametersPbeParametersThe password-based encryption (PBE) parameters to use when encrypting the key material.
destinationSpan<byte>The byte span to receive the PKCS#8 EncryptedPrivateKeyInfo data.
bytesWrittenintWhen this method returns, contains a value that indicates the number of bytes written to
destination. This parameter is treated as uninitialized.
Returns
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
destinationSpan<byte>The byte span to receive the PKCS#8 PrivateKeyInfo data.
bytesWrittenintWhen this method returns, contains a value that indicates the number of bytes written to
destination. This parameter is treated as uninitialized.
Returns
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
destinationSpan<byte>The byte span to receive the X.509 SubjectPublicKeyInfo data.
bytesWrittenintWhen this method returns, contains a value that indicates the number of bytes written to
destination. This parameter is treated as uninitialized.
Returns
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
dataReadOnlySpan<byte>The message bytes that were signed. May be empty.
signatureReadOnlySpan<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
| Product | Versions |
|---|---|
| .NET | 8, 10 |