cheatah
Module

ed25519

Public-key signatures (RFC 8032 Ed25519), implemented from scratch with no external crypto dependency. A secret seed signs; the derived public key verifies; a verifier holding only the public key cannot forge. Keys and signatures are lowercase hex; the message is raw bytes.

import io
import ed25519

let secret = ed25519.generate()           # fresh 32-byte seed (hex)
let pub = ed25519.public_key(secret)       # derive the public key (hex)
let sig = ed25519.sign(secret, "release v1")
io.print(ed25519.verify(pub, "release v1", sig))   # True
io.print(ed25519.verify(pub, "tampered", sig))     # False

Functions

  • generate() — a fresh 32-byte secret seed (64 hex chars) from the OS CSPRNG. Keep it secret; anyone with it can sign as you.

  • public_key(secret_hex) — derive the 32-byte public key (hex) from a secret seed.

  • sign(secret_hex, message) — a 64-byte signature (hex) over message (raw bytes). Deterministic: the same seed and message always produce the same signature.

  • verify(public_hex, message, signature_hex)true iff the signature is valid. Touches only public data, rejects non-canonical signatures (S ≥ L), and returns false (never raises) on malformed input.

The implementation is validated byte-for-byte against the RFC 8032 known-answer vectors and against OpenSSL. SHA-512 comes from the hashlib module (linked automatically). This is the same code the cheatah runtime links to verify a compiled module before loading it — see SECURITY.

Per-function docs (parameters, complexity, heap behavior) are in ed25519.hpp. Tested in ../tests/ed25519_test.cpp; ASan + Valgrind clean via the QA gate.

Functions

fn std::string public_key(std::string_view secret_hex) source#

Derive the 32-byte public key (hex) from a 32-byte secret seed (hex).

Computes the Ed25519 public key per RFC 8032 (SHA-512 of the seed, clamp, scalar multiply the base point). Throws std::invalid_argument if secret_hex is not exactly 64 hex chars.

Parameters
secret_hex

the secret seed as 64 hex chars.

Returns

the public key as 64 hex chars.

Complexity

O(1) (one fixed-base scalar multiplication).

Allocation

allocates the result string and a temporary decoded-seed string.

fn std::string generate() source#

Generate a fresh 32-byte secret seed from the OS CSPRNG, as 64 hex chars.

The returned seed is the private key; derive its public key with public_key(). NOT reproducible (uses os-level entropy) and must be kept secret. Throws std::runtime_error if the OS randomness source cannot be read.

Returns

a 64-char lowercase hex string (32 random bytes).

Complexity

O(1) plus a syscall.

Allocation

allocates the result string.

fn std::string sign(std::string_view secret_hex, std::string_view message) source#

Sign message with the secret seed secret_hex; returns a 64-byte signature (hex).

RFC 8032 Ed25519 signing (deterministic — no RNG, so the same seed and message always produce the same signature). The message is raw bytes of any length. Throws std::invalid_argument if secret_hex is not 64 hex chars.

Parameters
secret_hex

the secret seed as 64 hex chars.

message

the bytes to sign.

Returns

the signature as 128 hex chars (64 bytes).

Complexity

O(n) in the message length (two message-length SHA-512s) plus two fixed-base scalar multiplications (public-key derivation and R).

Allocation

allocates the signature string and two message-sized internal hash-input buffers (plus small seed/digest temporaries).

fn bool verify(std::string_view public_hex, std::string_view message, std::string_view signature_hex) source#

Verify that signature_hex is a valid Ed25519 signature of message under the public key public_hex.

Returns true iff valid.

Touches only public data, so it is safe to run on an untrusted host. Returns false (never throws) for a malformed public key/signature or a hex-decoding failure, so a caller can treat any non-true result as "reject".

Parameters
public_hex

the public key as 64 hex chars.

message

the signed bytes.

signature_hex

the signature as 128 hex chars.

Returns

true iff the signature verifies.

Complexity

O(n) in the message length plus two scalar multiplications.

Allocation

allocates internal buffers (the decoded key/signature strings and a message-sized hash-input buffer).

fn std::string from_hex(std::string_view hex) source#

Hex DECODE — the inverse of to_hex.

Accepts an even-length hex string in either digit case.

Parameters
hex

the hex text (both a-f and A-F accepted; no 0x prefix).

Returns

the decoded raw bytes (may contain embedded NULs).

Parameters
std::invalid_argument

on an odd length or a non-hex character.

Complexity

O(|hex|).

Allocation

the returned bytes.

fn std::string to_hex(const std::uint8_t *data, std::size_t n) source#

Lowercase-hex ENCODE overload for a raw byte buffer (the form the digest and Ed25519 paths use).

Parameters
data

pointer to the bytes.

n

the number of bytes.

Returns

the lowercase hex text (length 2*n).

Complexity

O(n).

Allocation

the returned string.