Skip to content

ed25519 - [mainnet]

Contains functions for:

  1. Ed25519 digital signatures: i.e., EdDSA signatures over Edwards25519 curves with co-factor 8
use 0x1::bcs;
use 0x1::error;
use 0x1::hash;
use 0x1::option;
use 0x1::type_info;

Constants

The size of a serialized public key, in bytes.

const PUBLIC_KEY_NUM_BYTES: u64 = 32;

Wrong number of bytes were given as input when deserializing an Ed25519 public key.

const E_WRONG_PUBKEY_SIZE: u64 = 1;

Wrong number of bytes were given as input when deserializing an Ed25519 signature.

const E_WRONG_SIGNATURE_SIZE: u64 = 2;

The size of a serialized signature, in bytes.

const SIGNATURE_NUM_BYTES: u64 = 64;

The identifier of the Ed25519 signature scheme, which is used when deriving Aptos authentication keys by hashing it together with an Ed25519 public key.

const SIGNATURE_SCHEME_ID: u8 = 0;

Structs

SignedMessage

A BCS-serializable message, which one can verify signatures on via signature_verify_strict_t

struct SignedMessage<MessageType> has drop
Fields
type_info: type_info::TypeInfo
inner: MessageType

UnvalidatedPublicKey

An unvalidated Ed25519 public key: not necessarily an elliptic curve point, just a sequence of 32 bytes

struct UnvalidatedPublicKey has copy, drop, store
Fields
bytes: vector<u8>

ValidatedPublicKey

A validated Ed25519 public key: not necessarily a prime-order point, could be mixed-order, but will never be a small-order point.

For now, this struct is not used in any verification functions, but it might be in the future.

struct ValidatedPublicKey has copy, drop, store
Fields
bytes: vector<u8>

Signature

A purported Ed25519 signature that can be verified via signature_verify_strict or signature_verify_strict_t.

struct Signature has copy, drop, store
Fields
bytes: vector<u8>

Functions

new_unvalidated_public_key_from_bytes

Parses the input 32 bytes as an unvalidated Ed25519 public key.

public fun new_unvalidated_public_key_from_bytes(bytes: vector<u8>): ed25519::UnvalidatedPublicKey
Implementation
public fun new_unvalidated_public_key_from_bytes(bytes: vector<u8>): UnvalidatedPublicKey {
assert!(bytes.length() == PUBLIC_KEY_NUM_BYTES, std::error::invalid_argument(E_WRONG_PUBKEY_SIZE));
UnvalidatedPublicKey { bytes }
}

new_validated_public_key_from_bytes

Parses the input 32 bytes as a validated Ed25519 public key.

public fun new_validated_public_key_from_bytes(bytes: vector<u8>): option::Option<ed25519::ValidatedPublicKey>
Implementation
public fun new_validated_public_key_from_bytes(bytes: vector<u8>): Option<ValidatedPublicKey> {
if (public_key_validate_internal(bytes)) {
option::some(ValidatedPublicKey {
bytes
})
} else {
option::none<ValidatedPublicKey>()
}
}

new_signature_from_bytes

Parses the input 64 bytes as a purported Ed25519 signature.

public fun new_signature_from_bytes(bytes: vector<u8>): ed25519::Signature
Implementation
public fun new_signature_from_bytes(bytes: vector<u8>): Signature {
assert!(bytes.length() == SIGNATURE_NUM_BYTES, std::error::invalid_argument(E_WRONG_SIGNATURE_SIZE));
Signature { bytes }
}

public_key_to_unvalidated

Converts a ValidatedPublicKey to an UnvalidatedPublicKey, which can be used in the strict verification APIs.

public fun public_key_to_unvalidated(pk: &ed25519::ValidatedPublicKey): ed25519::UnvalidatedPublicKey
Implementation
public fun public_key_to_unvalidated(pk: &ValidatedPublicKey): UnvalidatedPublicKey {
UnvalidatedPublicKey {
bytes: pk.bytes
}
}

public_key_into_unvalidated

Moves a ValidatedPublicKey into an UnvalidatedPublicKey, which can be used in the strict verification APIs.

public fun public_key_into_unvalidated(pk: ed25519::ValidatedPublicKey): ed25519::UnvalidatedPublicKey
Implementation
public fun public_key_into_unvalidated(pk: ValidatedPublicKey): UnvalidatedPublicKey {
UnvalidatedPublicKey {
bytes: pk.bytes
}
}

unvalidated_public_key_to_bytes

Serializes an UnvalidatedPublicKey struct to 32-bytes.

public fun unvalidated_public_key_to_bytes(pk: &ed25519::UnvalidatedPublicKey): vector<u8>
Implementation
public fun unvalidated_public_key_to_bytes(pk: &UnvalidatedPublicKey): vector<u8> {
pk.bytes
}

validated_public_key_to_bytes

Serializes an ValidatedPublicKey struct to 32-bytes.

public fun validated_public_key_to_bytes(pk: &ed25519::ValidatedPublicKey): vector<u8>
Implementation
public fun validated_public_key_to_bytes(pk: &ValidatedPublicKey): vector<u8> {
pk.bytes
}

signature_to_bytes

Serializes a Signature struct to 64-bytes.

public fun signature_to_bytes(sig: &ed25519::Signature): vector<u8>
Implementation
public fun signature_to_bytes(sig: &Signature): vector<u8> {
sig.bytes
}

public_key_validate

Takes in an unvalidated public key and attempts to validate it. Returns Some(ValidatedPublicKey) if successful and None otherwise.

public fun public_key_validate(pk: &ed25519::UnvalidatedPublicKey): option::Option<ed25519::ValidatedPublicKey>
Implementation
public fun public_key_validate(pk: &UnvalidatedPublicKey): Option<ValidatedPublicKey> {
new_validated_public_key_from_bytes(pk.bytes)
}

signature_verify_strict

Verifies a purported Ed25519 signature under an unvalidated public_key on the specified message. This call will validate the public key by checking it is NOT in the small subgroup.

public fun signature_verify_strict(signature: &ed25519::Signature, public_key: &ed25519::UnvalidatedPublicKey, message: vector<u8>): bool
Implementation
public fun signature_verify_strict(
signature: &Signature,
public_key: &UnvalidatedPublicKey,
message: vector<u8>
): bool {
signature_verify_strict_internal(signature.bytes, public_key.bytes, message)
}

signature_verify_strict_t

This function is used to verify a signature on any BCS-serializable type T. For now, it is used to verify the proof of private key ownership when rotating authentication keys.

public fun signature_verify_strict_t<T: drop>(signature: &ed25519::Signature, public_key: &ed25519::UnvalidatedPublicKey, data: T): bool
Implementation
public fun signature_verify_strict_t<T: drop>(signature: &Signature, public_key: &UnvalidatedPublicKey, data: T): bool {
let encoded = SignedMessage {
type_info: type_info::type_of<T>(),
inner: data,
};
signature_verify_strict_internal(signature.bytes, public_key.bytes, bcs::to_bytes(&encoded))
}

new_signed_message

Helper method to construct a SignedMessage struct.

public fun new_signed_message<T: drop>(data: T): ed25519::SignedMessage<T>
Implementation
public fun new_signed_message<T: drop>(data: T): SignedMessage<T> {
SignedMessage {
type_info: type_info::type_of<T>(),
inner: data,
}
}

unvalidated_public_key_to_authentication_key

Derives the Aptos-specific authentication key of the given Ed25519 public key.

public fun unvalidated_public_key_to_authentication_key(pk: &ed25519::UnvalidatedPublicKey): vector<u8>
Implementation
public fun unvalidated_public_key_to_authentication_key(pk: &UnvalidatedPublicKey): vector<u8> {
public_key_bytes_to_authentication_key(pk.bytes)
}

validated_public_key_to_authentication_key

Derives the Aptos-specific authentication key of the given Ed25519 public key.

public fun validated_public_key_to_authentication_key(pk: &ed25519::ValidatedPublicKey): vector<u8>
Implementation
public fun validated_public_key_to_authentication_key(pk: &ValidatedPublicKey): vector<u8> {
public_key_bytes_to_authentication_key(pk.bytes)
}

public_key_bytes_to_authentication_key

Derives the Aptos-specific authentication key of the given Ed25519 public key.

fun public_key_bytes_to_authentication_key(pk_bytes: vector<u8>): vector<u8>
Implementation
fun public_key_bytes_to_authentication_key(pk_bytes: vector<u8>): vector<u8> {
pk_bytes.push_back(SIGNATURE_SCHEME_ID);
std::hash::sha3_256(pk_bytes)
}

public_key_validate_internal

Return true if the bytes in public_key can be parsed as a valid Ed25519 public key: i.e., it passes points-on-curve and not-in-small-subgroup checks. Returns false otherwise.

fun public_key_validate_internal(bytes: vector<u8>): bool
Implementation
native fun public_key_validate_internal(bytes: vector<u8>): bool;

signature_verify_strict_internal

Return true if the Ed25519 signature on message verifies against the Ed25519 public_key. Returns false if either:

  • signature or public key are of wrong sizes
  • public_key does not pass points-on-curve or not-in-small-subgroup checks,
  • signature does not pass points-on-curve or not-in-small-subgroup checks,
  • the signature on message does not verify.
fun signature_verify_strict_internal(signature: vector<u8>, public_key: vector<u8>, message: vector<u8>): bool
Implementation
native fun signature_verify_strict_internal(
signature: vector<u8>,
public_key: vector<u8>,
message: vector<u8>
): bool;

Specification

new_unvalidated_public_key_from_bytes

public fun new_unvalidated_public_key_from_bytes(bytes: vector<u8>): ed25519::UnvalidatedPublicKey
include NewUnvalidatedPublicKeyFromBytesAbortsIf;
ensures result == UnvalidatedPublicKey { bytes };
schema NewUnvalidatedPublicKeyFromBytesAbortsIf {
bytes: vector<u8>;
aborts_if len(bytes) != PUBLIC_KEY_NUM_BYTES;
}

new_validated_public_key_from_bytes

public fun new_validated_public_key_from_bytes(bytes: vector<u8>): option::Option<ed25519::ValidatedPublicKey>
aborts_if false;
let cond = spec_public_key_validate_internal(bytes);
ensures cond ==> result == option::spec_some(ValidatedPublicKey{bytes});
ensures !cond ==> result == option::spec_none<ValidatedPublicKey>();

new_signature_from_bytes

public fun new_signature_from_bytes(bytes: vector<u8>): ed25519::Signature
include NewSignatureFromBytesAbortsIf;
ensures result == Signature { bytes };
schema NewSignatureFromBytesAbortsIf {
bytes: vector<u8>;
aborts_if len(bytes) != SIGNATURE_NUM_BYTES;
}

public_key_bytes_to_authentication_key

fun public_key_bytes_to_authentication_key(pk_bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if false;
ensures [abstract] result == spec_public_key_bytes_to_authentication_key(pk_bytes);

public_key_validate_internal

fun public_key_validate_internal(bytes: vector<u8>): bool
pragma opaque;
aborts_if false;
ensures result == spec_public_key_validate_internal(bytes);

signature_verify_strict_internal

fun signature_verify_strict_internal(signature: vector<u8>, public_key: vector<u8>, message: vector<u8>): bool
pragma opaque;
aborts_if false;
ensures result == spec_signature_verify_strict_internal(signature, public_key, message);

Helper functions

fun spec_signature_verify_strict_internal(
signature: vector<u8>,
public_key: vector<u8>,
message: vector<u8>
): bool;
fun spec_public_key_validate_internal(bytes: vector<u8>): bool;
fun spec_public_key_bytes_to_authentication_key(pk_bytes: vector<u8>): vector<u8>;
fun spec_signature_verify_strict_t<T>(signature: Signature, public_key: UnvalidatedPublicKey, data: T): bool {
let encoded = SignedMessage<T> {
type_info: type_info::type_of<T>(),
inner: data,
};
let message = bcs::serialize(encoded);
spec_signature_verify_strict_internal(signature.bytes, public_key.bytes, message)
}