Ed25519 signatures

This module provides the protocol layer for Ed25519 as specified by RFC 8032. The underlying curve group is the native twisted Edwards group provided by sage.schemes.elliptic_curves.ell_edwards. Keeping the two layers separate is important: a generic twisted Edwards curve has an equation and a group law, while Ed25519 additionally fixes the field, parameters, base point, cofactor, hash function, scalar pruning, and byte encoding.

The public functions implement deterministic Ed25519, Ed25519ctx, and Ed25519ph signing and verification using the 32-byte private-key seed format from RFC 8032. Ed25519ctx separates signatures by a caller-supplied context; Ed25519ph hashes the message before signing and can also use a context. The three variants have different signature domains and are not interchangeable:

sage: seed = bytes.fromhex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
sage: public_key = ed25519_public_key(seed)
sage: public_key.hex()
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
sage: signature = ed25519_sign(seed, b"")
sage: signature.hex()
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
sage: ed25519_verify(public_key, b"", signature)
True
>>> from sage.all import *
>>> seed = bytes.fromhex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
>>> public_key = ed25519_public_key(seed)
>>> public_key.hex()
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
>>> signature = ed25519_sign(seed, b"")
>>> signature.hex()
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
>>> ed25519_verify(public_key, b"", signature)
True
seed = bytes.fromhex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
public_key = ed25519_public_key(seed)
public_key.hex()
signature = ed25519_sign(seed, b"")
signature.hex()
ed25519_verify(public_key, b"", signature)

For an object-oriented interface that bundles the variant and context into a single scheme object with the secret_key / public_key / sign / verify operation shape of the digital-signature framework proposed in Issue #42856, use Ed25519SignatureScheme.

The curve constructor and base point are cached, so ordinary Sage additive group operations can be used directly without a second hand-written scalar multiplication implementation:

sage: C = Ed25519()
sage: B = Ed25519BasePoint()
sage: C(B) == B
True
sage: ed25519_decode(ed25519_encode(B)) == B
True
>>> from sage.all import *
>>> C = Ed25519()
>>> B = Ed25519BasePoint()
>>> C(B) == B
True
>>> ed25519_decode(ed25519_encode(B)) == B
True
C = Ed25519()
B = Ed25519BasePoint()
C(B) == B
ed25519_decode(ed25519_encode(B)) == B

This module intentionally does not provide X25519 or an interchangeable private-key object. X25519 is a different protocol using the Montgomery form and Ed25519’s signing key is a seed, not the already-pruned scalar.

REFERENCES:

AUTHORS:

  • SageMath developers (2026): initial Ed25519 protocol support

sage.crypto.ed25519.Ed25519()[source]

Return the standard Ed25519 twisted Edwards curve.

The returned parent is the curve

\[-x^2 + y^2 = 1 + d x^2 y^2, \qquad d = -121665/121666\]

over GF(2^255 - 19). The protocol-specific encoding and signing functions are ed25519_encode(), ed25519_decode(), ed25519_sign(), and ed25519_verify().

EXAMPLES:

sage: C = Ed25519()
sage: C.base_ring().order() == ED25519_FIELD_SIZE
True
sage: C.a() == -1
True
sage: C.d() == C.base_ring()(-121665) / C.base_ring()(121666)
True
>>> from sage.all import *
>>> C = Ed25519()
>>> C.base_ring().order() == ED25519_FIELD_SIZE
True
>>> C.a() == -Integer(1)
True
>>> C.d() == C.base_ring()(-Integer(121665)) / C.base_ring()(Integer(121666))
True
C = Ed25519()
C.base_ring().order() == ED25519_FIELD_SIZE
C.a() == -1
C.d() == C.base_ring()(-121665) / C.base_ring()(121666)
sage.crypto.ed25519.Ed25519BasePoint()[source]

Return the standard Ed25519 base point B.

EXAMPLES:

sage: B = Ed25519BasePoint()
sage: B.parent() is Ed25519()
True
sage: B.coordinates() == (ED25519_BASE_X, ED25519_BASE_Y)
True
>>> from sage.all import *
>>> B = Ed25519BasePoint()
>>> B.parent() is Ed25519()
True
>>> B.coordinates() == (ED25519_BASE_X, ED25519_BASE_Y)
True
B = Ed25519BasePoint()
B.parent() is Ed25519()
B.coordinates() == (ED25519_BASE_X, ED25519_BASE_Y)
class sage.crypto.ed25519.Ed25519SignatureScheme(variant='ed25519', context=b'')[source]

Bases: object

Ed25519, Ed25519ctx and Ed25519ph as a digital-signature scheme object.

This is the object-oriented counterpart of the module-level functions: one instance bundles the RFC 8032 variant and (for ctx/ph) the context string, which removes the risk of signing and verifying with mismatched domain parameters. When the digital-signature framework of Issue #42856 is available, this class is a DigitalSignatureBase subclass and can be used uniformly with the other schemes of that framework.

INPUT:

  • variant – one of 'ed25519', 'ed25519ctx', 'ed25519ph'

  • context – bytes-like application context (at most 255 bytes), only used by the 'ed25519ctx' and 'ed25519ph' variants; ignored for pure Ed25519

Keys are the RFC 8032 32-byte seed (secret) and 32-byte encoded point (public). Messages are bytes-like; Ed25519ph hashes them with SHA-512 internally, so pass the raw message, not its prehash.

EXAMPLES:

sage: from sage.crypto.ed25519 import Ed25519SignatureScheme
sage: ed = Ed25519SignatureScheme('ed25519ph', b'foo')
sage: secret = ed.secret_key()
sage: public = ed.public_key(secret)
sage: signature, signed_message = ed.sign(b'attack at dawn', secret)
sage: ed.verify(public, signature, signed_message)
True
>>> from sage.all import *
>>> from sage.crypto.ed25519 import Ed25519SignatureScheme
>>> ed = Ed25519SignatureScheme('ed25519ph', b'foo')
>>> secret = ed.secret_key()
>>> public = ed.public_key(secret)
>>> signature, signed_message = ed.sign(b'attack at dawn', secret)
>>> ed.verify(public, signature, signed_message)
True
from sage.crypto.ed25519 import Ed25519SignatureScheme
ed = Ed25519SignatureScheme('ed25519ph', b'foo')
secret = ed.secret_key()
public = ed.public_key(secret)
signature, signed_message = ed.sign(b'attack at dawn', secret)
ed.verify(public, signature, signed_message)

A signature made under one context does not verify under another:

sage: other = Ed25519SignatureScheme('ed25519ph', b'bar')
sage: other.verify(public, signature, signed_message)
False
>>> from sage.all import *
>>> other = Ed25519SignatureScheme('ed25519ph', b'bar')
>>> other.verify(public, signature, signed_message)
False
other = Ed25519SignatureScheme('ed25519ph', b'bar')
other.verify(public, signature, signed_message)

The pure variant reproduces the RFC 8032 section 7.1 test vector:

sage: pure = Ed25519SignatureScheme('ed25519')
sage: seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
sage: signature, _ = pure.sign(b'', seed)
sage: signature.hex()
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
>>> from sage.all import *
>>> pure = Ed25519SignatureScheme('ed25519')
>>> seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
>>> signature, _ = pure.sign(b'', seed)
>>> signature.hex()
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
pure = Ed25519SignatureScheme('ed25519')
seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
signature, _ = pure.sign(b'', seed)
signature.hex()
context()[source]

Return the context string (empty for pure Ed25519).

public_key(secret_key)[source]

Return the 32-byte public key of a 32-byte seed.

EXAMPLES:

sage: from sage.crypto.ed25519 import Ed25519SignatureScheme
sage: ed = Ed25519SignatureScheme()
sage: seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
sage: ed.public_key(seed).hex()
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
>>> from sage.all import *
>>> from sage.crypto.ed25519 import Ed25519SignatureScheme
>>> ed = Ed25519SignatureScheme()
>>> seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
>>> ed.public_key(seed).hex()
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
from sage.crypto.ed25519 import Ed25519SignatureScheme
ed = Ed25519SignatureScheme()
seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
ed.public_key(seed).hex()
secret_key()[source]

Return a fresh random 32-byte Ed25519 seed.

EXAMPLES:

sage: from sage.crypto.ed25519 import Ed25519SignatureScheme
sage: ed = Ed25519SignatureScheme()
sage: sk = ed.secret_key()
sage: len(sk)
32
>>> from sage.all import *
>>> from sage.crypto.ed25519 import Ed25519SignatureScheme
>>> ed = Ed25519SignatureScheme()
>>> sk = ed.secret_key()
>>> len(sk)
32
from sage.crypto.ed25519 import Ed25519SignatureScheme
ed = Ed25519SignatureScheme()
sk = ed.secret_key()
len(sk)
sign(message, secret_key, nonce=None)[source]

Sign message with a 32-byte seed and return (signature, message).

Ed25519 nonces are derived deterministically from the secret key and the message, so an explicit nonce is not supported; the parameter is accepted and ignored to keep the signature-shape of the framework.

EXAMPLES:

sage: from sage.crypto.ed25519 import Ed25519SignatureScheme
sage: ed = Ed25519SignatureScheme('ed25519ctx', b'foo')
sage: seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
sage: message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
sage: signature, signed = ed.sign(message, seed)
sage: signature.hex() == ed25519ctx_sign(seed, message, b'foo').hex()
True
>>> from sage.all import *
>>> from sage.crypto.ed25519 import Ed25519SignatureScheme
>>> ed = Ed25519SignatureScheme('ed25519ctx', b'foo')
>>> seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
>>> message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
>>> signature, signed = ed.sign(message, seed)
>>> signature.hex() == ed25519ctx_sign(seed, message, b'foo').hex()
True
from sage.crypto.ed25519 import Ed25519SignatureScheme
ed = Ed25519SignatureScheme('ed25519ctx', b'foo')
seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
signature, signed = ed.sign(message, seed)
signature.hex() == ed25519ctx_sign(seed, message, b'foo').hex()
variant()[source]

Return the RFC 8032 variant of this scheme.

verify(public_key, signature, message)[source]

Return whether signature is a valid signature of message.

EXAMPLES:

sage: from sage.crypto.ed25519 import Ed25519SignatureScheme
sage: ed = Ed25519SignatureScheme('ed25519ph')
sage: seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
sage: public = ed.public_key(seed)
sage: signature, message = ed.sign(b'abc', seed)
sage: ed.verify(public, signature, message)
True
sage: ed.verify(public, signature, b'abd')
False
>>> from sage.all import *
>>> from sage.crypto.ed25519 import Ed25519SignatureScheme
>>> ed = Ed25519SignatureScheme('ed25519ph')
>>> seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
>>> public = ed.public_key(seed)
>>> signature, message = ed.sign(b'abc', seed)
>>> ed.verify(public, signature, message)
True
>>> ed.verify(public, signature, b'abd')
False
from sage.crypto.ed25519 import Ed25519SignatureScheme
ed = Ed25519SignatureScheme('ed25519ph')
seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
public = ed.public_key(seed)
signature, message = ed.sign(b'abc', seed)
ed.verify(public, signature, message)
ed.verify(public, signature, b'abd')
sage.crypto.ed25519.ed25519_decode(data)[source]

Decode a canonical 32-byte Ed25519 point encoding.

The square root is recovered in GF(2^255 - 19) using the p = 5 mod 8 square-root method. The returned point is a point on the full curve; callers that need a prime-order point must apply the protocol’s cofactor handling.

EXAMPLES:

sage: ed25519_decode(bytes.fromhex('5866666666666666666666666666666666666666666666666666666666666666')) == Ed25519BasePoint()
True
sage: ed25519_decode(b'\xff' * 32)
Traceback (most recent call last):
...
ValueError: the encoded y-coordinate is not canonical
>>> from sage.all import *
>>> ed25519_decode(bytes.fromhex('5866666666666666666666666666666666666666666666666666666666666666')) == Ed25519BasePoint()
True
>>> ed25519_decode(b'\xff' * Integer(32))
Traceback (most recent call last):
...
ValueError: the encoded y-coordinate is not canonical
ed25519_decode(bytes.fromhex('5866666666666666666666666666666666666666666666666666666666666666')) == Ed25519BasePoint()
ed25519_decode(b'\xff' * 32)
sage.crypto.ed25519.ed25519_encode(point)[source]

Encode an Ed25519 point as 32 little-endian bytes.

The low 255 bits encode the affine y coordinate and the high bit encodes the least significant bit of x. Coordinates are required to be canonical field elements and point must belong to Ed25519().

EXAMPLES:

sage: ed25519_encode(Ed25519BasePoint()).hex()
'5866666666666666666666666666666666666666666666666666666666666666'
sage: ed25519_decode(ed25519_encode(Ed25519BasePoint())) == Ed25519BasePoint()
True
>>> from sage.all import *
>>> ed25519_encode(Ed25519BasePoint()).hex()
'5866666666666666666666666666666666666666666666666666666666666666'
>>> ed25519_decode(ed25519_encode(Ed25519BasePoint())) == Ed25519BasePoint()
True
ed25519_encode(Ed25519BasePoint()).hex()
ed25519_decode(ed25519_encode(Ed25519BasePoint())) == Ed25519BasePoint()
sage.crypto.ed25519.ed25519_public_key(seed)[source]

Derive the 32-byte Ed25519 public key from a 32-byte seed.

EXAMPLES:

sage: seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
sage: ed25519_public_key(seed).hex()
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
>>> from sage.all import *
>>> seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
>>> ed25519_public_key(seed).hex()
'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
ed25519_public_key(seed).hex()
sage.crypto.ed25519.ed25519_sign(seed, message)[source]

Create a deterministic pure Ed25519 signature.

seed is the 32-byte private-key seed and message is a bytes-like message. The result is the 64-byte concatenation ENC(R) || ENC(S).

EXAMPLES:

sage: seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
sage: ed25519_sign(seed, b'').hex()
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
>>> from sage.all import *
>>> seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
>>> ed25519_sign(seed, b'').hex()
'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b'
seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
ed25519_sign(seed, b'').hex()
sage.crypto.ed25519.ed25519_verify(public_key, message, signature)[source]

Verify an Ed25519 signature.

The RFC 8032 verification equation is checked with the cofactor:

\[[8][S]B = [8]R + [8][k]A,\]

where k is the reduced SHA-512 challenge. Malformed encodings and non-canonical S values return False.

EXAMPLES:

sage: seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
sage: public_key = ed25519_public_key(seed)
sage: signature = ed25519_sign(seed, b'')
sage: ed25519_verify(public_key, b'', signature)
True
sage: ed25519_verify(public_key, b'bad', signature)
False
sage: import operator
sage: ed25519_verify(public_key, b'', signature[:-1] + bytes([operator.xor(signature[-1], 1)]))
False
>>> from sage.all import *
>>> seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
>>> public_key = ed25519_public_key(seed)
>>> signature = ed25519_sign(seed, b'')
>>> ed25519_verify(public_key, b'', signature)
True
>>> ed25519_verify(public_key, b'bad', signature)
False
>>> import operator
>>> ed25519_verify(public_key, b'', signature[:-Integer(1)] + bytes([operator.xor(signature[-Integer(1)], Integer(1))]))
False
seed = bytes.fromhex('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60')
public_key = ed25519_public_key(seed)
signature = ed25519_sign(seed, b'')
ed25519_verify(public_key, b'', signature)
ed25519_verify(public_key, b'bad', signature)
import operator
ed25519_verify(public_key, b'', signature[:-1] + bytes([operator.xor(signature[-1], 1)]))
sage.crypto.ed25519.ed25519ctx_sign(seed, message, context)[source]

Create an Ed25519ctx signature with a context of at most 255 bytes.

An empty context is permitted, but still uses the Ed25519ctx domain and does not produce a pure Ed25519 signature. The context is bytes-like and must match exactly when verifying.

EXAMPLES:

sage: seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
sage: message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
sage: ed25519ctx_sign(seed, message, b'foo').hex()  # RFC 8032, Section 7.2
'55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d'
sage: ed25519ctx_sign(seed, message, b'bar').hex()
'fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d'
>>> from sage.all import *
>>> seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
>>> message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
>>> ed25519ctx_sign(seed, message, b'foo').hex()  # RFC 8032, Section 7.2
'55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d'
>>> ed25519ctx_sign(seed, message, b'bar').hex()
'fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d'
seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
ed25519ctx_sign(seed, message, b'foo').hex()  # RFC 8032, Section 7.2
ed25519ctx_sign(seed, message, b'bar').hex()
sage.crypto.ed25519.ed25519ctx_verify(public_key, message, signature, context)[source]

Verify an Ed25519ctx signature under the given context.

Return False for malformed input or a context longer than 255 bytes.

EXAMPLES:

sage: seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
sage: public_key = ed25519_public_key(seed)
sage: message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
sage: signature = ed25519ctx_sign(seed, message, b'foo')
sage: ed25519ctx_verify(public_key, message, signature, b'foo')
True
sage: ed25519ctx_verify(public_key, message, signature, b'bar')
False
sage: ed25519_verify(public_key, message, signature)
False
sage: ed25519ctx_verify(public_key, message, signature, b'x' * 256)
False
>>> from sage.all import *
>>> seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
>>> public_key = ed25519_public_key(seed)
>>> message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
>>> signature = ed25519ctx_sign(seed, message, b'foo')
>>> ed25519ctx_verify(public_key, message, signature, b'foo')
True
>>> ed25519ctx_verify(public_key, message, signature, b'bar')
False
>>> ed25519_verify(public_key, message, signature)
False
>>> ed25519ctx_verify(public_key, message, signature, b'x' * Integer(256))
False
seed = bytes.fromhex('0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6')
public_key = ed25519_public_key(seed)
message = bytes.fromhex('f726936d19c800494e3fdaff20b276a8')
signature = ed25519ctx_sign(seed, message, b'foo')
ed25519ctx_verify(public_key, message, signature, b'foo')
ed25519ctx_verify(public_key, message, signature, b'bar')
ed25519_verify(public_key, message, signature)
ed25519ctx_verify(public_key, message, signature, b'x' * 256)
sage.crypto.ed25519.ed25519ph_sign(seed, message, context=b'')[source]

Create an Ed25519ph signature of a raw message.

The message is hashed once with SHA-512 before the Ed25519ph nonce and challenge hashes. Do not prehash it before calling this function. context is bytes-like, defaults to empty, and is limited to 255 bytes.

EXAMPLES:

sage: seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
sage: ed25519ph_sign(seed, b'abc').hex()  # RFC 8032, Section 7.3
'98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406'
sage: import hashlib
sage: ed25519ph_sign(seed, b'abc') != ed25519_sign(seed, hashlib.sha512(b'abc').digest())
True
>>> from sage.all import *
>>> seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
>>> ed25519ph_sign(seed, b'abc').hex()  # RFC 8032, Section 7.3
'98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406'
>>> import hashlib
>>> ed25519ph_sign(seed, b'abc') != ed25519_sign(seed, hashlib.sha512(b'abc').digest())
True
seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
ed25519ph_sign(seed, b'abc').hex()  # RFC 8032, Section 7.3
import hashlib
ed25519ph_sign(seed, b'abc') != ed25519_sign(seed, hashlib.sha512(b'abc').digest())
sage.crypto.ed25519.ed25519ph_verify(public_key, message, signature, context=b'')[source]

Verify an Ed25519ph signature of a raw message.

context defaults to empty and must contain at most 255 bytes. Return False for malformed input.

EXAMPLES:

sage: seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
sage: public_key = ed25519_public_key(seed)
sage: signature = ed25519ph_sign(seed, b'abc')
sage: ed25519ph_verify(public_key, b'abc', signature)
True
sage: ed25519ph_verify(public_key, b'abd', signature)
False
sage: ed25519ph_verify(public_key, b'abc', signature, b'foo')
False
sage: ed25519_verify(public_key, b'abc', signature)
False
>>> from sage.all import *
>>> seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
>>> public_key = ed25519_public_key(seed)
>>> signature = ed25519ph_sign(seed, b'abc')
>>> ed25519ph_verify(public_key, b'abc', signature)
True
>>> ed25519ph_verify(public_key, b'abd', signature)
False
>>> ed25519ph_verify(public_key, b'abc', signature, b'foo')
False
>>> ed25519_verify(public_key, b'abc', signature)
False
seed = bytes.fromhex('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42')
public_key = ed25519_public_key(seed)
signature = ed25519ph_sign(seed, b'abc')
ed25519ph_verify(public_key, b'abc', signature)
ed25519ph_verify(public_key, b'abd', signature)
ed25519ph_verify(public_key, b'abc', signature, b'foo')
ed25519_verify(public_key, b'abc', signature)