Reference

std/signature/ed25519

std/signature/src/ed25519.trb

Ed25519 (RFC 8032 section 5.1): Ed25519PrivateKey signs, Ed25519PublicKey verifies, and Ed25519Signature is the 64 bytes between them. Three capsules, each made by a factory that checks what it is given, so a public key is always a point of the curve and a signature always has an S below the group order.

A private key is its 32-byte seed; everything else - the secret scalar, the prefix the nonce is hashed from, and the public key - is derived from the seed once, when the key is made. Signing is deterministic: the same key and message give the same signature, and no randomness is needed after the seed.

type Ed25519PrivateKey

type Ed25519PrivateKey with Show, Encode

An Ed25519 private key: the 32-byte seed RFC 8032 calls the private key, with the secret scalar, the prefix and the public key derived from it once. It signs with Ed25519PrivateKey.signature.

Its Show and its Encode write the public key and never the seed, so a key that ends up in a log line or in an encoded configuration does not leak; Ed25519PrivateKey.seed is the one way to the secret.

Examples

const seed: List<UInt8> = List.filled 32, 7
const key = Ed25519PrivateKey.fromSeed(seed).expect("32 bytes")
const message = "a release of acme/http".bytes().toList()
const signature = key.signature message
print key.publicKey().verifies(message, signature)

Pitfalls

  • Where the seed comes from is the caller's: std/signature makes no randomness (docs/design/RANDOM.md). A seed has to be 32 bytes of the system's source of randomness, never a password or a hash of one.
  • == compares the seeds byte by byte and stops at the first difference, which is not constant time; compare public keys instead.

fn fromSeed

static fn fromSeed(seed: Bytes): Result<Self, SignatureError>

The key of a 32-byte seed (RFC 8032 section 5.1.5). One multiplication of the base point, the cost of a signature.

Errors

fn fromHex

static fn fromHex(text: String): Result<Self, SignatureError>

The key of a seed written as 64 hexadecimal digits, either case: how a key comes out of an environment variable.

Errors

fn seed

fn seed(): List<UInt8>

The 32 bytes of the seed: the secret itself, for the one place that keeps it.

fn seedHex

fn seedHex(): String

The seed as 64 lowercase hexadecimal digits, which Ed25519PrivateKey.fromHex reads back.

fn publicKey

fn publicKey(): Ed25519PublicKey

The public key that verifies what this key signs.

fn signature

fn signature(message: Bytes): Ed25519Signature

The signature of message (RFC 8032 section 5.1.6): R = r B for the nonce r hashed from the prefix and the message, then S = r + k s modulo L for the challenge k hashed from R, the public key and the message. The multiplication of the base point and the arithmetic on the secret scalar take the same steps for every key and message.

fn show

fn show(): String

Ed25519PrivateKey(public key <hex>): the seed is never shown.

fn encode

fn encode<Target: Encoder>(var target: Target)

What Ed25519PrivateKey.show writes, as a string: an encoded configuration never carries the seed.

type Ed25519PublicKey

type Ed25519PublicKey with Show, Equals, Hash, TryFrom<String, SignatureError>

An Ed25519 public key: 32 bytes that encode a point of the curve, checked when the key is made - a y below p, an x that exists, and the canonical sign (RFC 8032 section 5.1.3). It verifies with Ed25519PublicKey.verifies.

Written as text it is 64 lowercase hexadecimal digits: Ed25519PublicKey.hex, its show() and String.from(key) write them, and Ed25519PublicKey.tryFrom(text) reads them back, which is also how the key is encoded and decoded.

Examples

const key = Ed25519PublicKey.tryFrom "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"
print key.isOk()

fn fromBytes

static fn fromBytes(bytes: Bytes): Result<Self, SignatureError>

The key 32 bytes encode.

Errors

fn tryFrom

static fn tryFrom(value: String): Result<Self, SignatureError>

The key 64 hexadecimal digits of either case write.

Errors

fn bytes

fn bytes(): List<UInt8>

The 32 bytes of the encoding.

fn hex

fn hex(): String

The 32 bytes as 64 lowercase hexadecimal digits.

fn show

fn show(): String

The same as Ed25519PublicKey.hex.

fn equals

fn equals(other: Self): Bool

Whether the two keys are the same 32 bytes: the point is derived from them, in whichever limbs it came out.

fn hash

fn hash(): Int

The hash of the 32 bytes, so that a key is a key of a Map or a member of a Set by its bytes alone.

fn verifies

fn verifies(message: Bytes, signature: Ed25519Signature): Bool

Whether signature is this key's signature of message (RFC 8032 section 5.1.7): with k the challenge hashed from R, the key and the message, whether S B - k A encodes as R. That is the equation without the cofactor, as ref10, libsodium and OpenSSL check it; the S of the signature was checked to be below L when the signature was made.

It takes variable time - everything it reads is public - and about as long as three signatures.

extend String with From<Ed25519PublicKey>

extend String with From<Ed25519PublicKey>

A public key as its 64 lowercase hexadecimal digits: the way back of Ed25519PublicKey.tryFrom.

fn from

static fn from(value: Ed25519PublicKey): Self

type Ed25519Signature

type Ed25519Signature with Show, TryFrom<String, SignatureError>

An Ed25519 signature: 64 bytes, the encoded point R and then the scalar S, checked to be below the group order L when the signature is made (RFC 8032 section 5.1.7). As text it is 128 lowercase hexadecimal digits, read back by Ed25519Signature.tryFrom.

fn fromBytes

static fn fromBytes(bytes: Bytes): Result<Self, SignatureError>

The signature 64 bytes are.

Errors

fn tryFrom

static fn tryFrom(value: String): Result<Self, SignatureError>

The signature 128 hexadecimal digits of either case write.

Errors

fn bytes

fn bytes(): List<UInt8>

The 64 bytes: R, then S.

fn hex

fn hex(): String

The 64 bytes as 128 lowercase hexadecimal digits.

fn show

fn show(): String

The same as Ed25519Signature.hex.

extend String with From<Ed25519Signature>

extend String with From<Ed25519Signature>

A signature as its 128 lowercase hexadecimal digits: the way back of Ed25519Signature.tryFrom.

fn from

static fn from(value: Ed25519Signature): Self