Introduction

This document is WORK IN PROGRESS. While the document
has this warning, check with your local cryptographer
whether the final solution is correct for your 
particular use case.

This document forms the IOG Cryptography Handbook, which aims to provide a go-to for engineers having to make a choice on which implementations to use for given cryptographic primitives. This document contains a specification of all the cryptographic primitives being used in production, or in testing phase, and at least a reference to the ongoing efforts of other cryptographic primitives.

The target audience for the Handbook is everyone working on a project associated with an IOG product, or within the Cardano ecosystem. This is also the set of target contributors for the Handbook! Anyone can submit a change proposal as a PR (see 'Contributing').

Purpose

The purpose of this handbook is both descriptive and to list existing implementations:

  • Firstly, it lists particular implementations for given cryptographic primitives that are being used, or have been reviewed, by IOG matter experts.
  • Secondly, it describes the cryptographic primitives in detail (or points interested reader to further material), to allow engineers to choose alternative implementation which are compatible with the primitives used by IOG.

Goals

The goals of the Handbook are to:

  • Provide a place to record all cryptographic libraries being used in IOG projects.
  • Present a sufficient level of detail of the cryptographic primitives to allow engineers to make independent decisions without having to contact matter experts or look into the source code.
  • Encourage consistency across the organization in order to minimize cognitive overheads from unnecessary differences.
  • Avoid implementing of primitives that already exist and/or are being used in IOG.
  • List common mistakes when handling with these type of libraries.

Non-goals

The following are explicitly not goals of the Handbook:

  • The recommended libraries are by no means flawless. As in any piece of software, the libraries hereby listed can have bugs.
  • Provide an exhaustive list of all available implementations in all languages. We only have a limited number of cryptographers, and this list will grow as we look into existing implementation of used primitives.

The Handbook is very new and will gradually acquire more content over time. We hope to improve all of this over time!

Contributing

If a project needs a particular primitive, which is not present in this document, the mechanism to include is simple. Add an issue to the repo, specifying why such a primitive is of interest, and how it would be used. To make the discussion more effective, it is also of interest to link references to the specification, or available implementations.

Ed25519

Ed25519 is the signature scheme being used in Cardano, and supported in Plutus. Ed25519 is an instantiation of the EdDSA over the Edwards25519 elliptic curve.

Implementation and bindings

We currently relly in the implementation available in version 1.0.18 of libsodium. We have analysed, and recommend, bindings in the following languages:

  • Haskell: Available in cardano-base
  • Rust: Made available by the original author of libsodium
  • Javascript: Made available by the original author of libsodium (among others)

There also exist other implementations that offer a compatible signing algorithm which do not require the full usage of libsodium. The list we have analaysed and recommend is the following:

  • Rust: ed25519-dalek, using the verify_strict() function.
  • Javascript: tweetnacl-js, though the verification criteria of this library is more permissive, meaning that a valid signature for tweetnacl-js might not be valid for Cardano.

Common mistakes

An ed25519 signature consists of two values , where is an elliptic curve point and is a scalar. A common mistake when deserialising the scalar is to compute it modulo in case that is larger than . This must be avoided, specifically in consensus critical scenarios.

Another common mistake is what criteria to use when deserialising an elliptic curve point. If none of the libraries listed above are used, the engineer should carefully read the sections below to understand the details, and the verification criteria used in Cardano.

KES

In Cardano, nodes use Key Evolving Signatures (KES). This is another asymmetric key cryptographic scheme, also relying on the use of public and private key pairs. These signature schemes provide forward cryptographic security, meaning that a compromised key does not make it easier for an adversary to forge a signature that allegedly had been signed in the past.

In KES, the public verification key stays constant, but the corresponding private key evolves incrementally. For this reason, KES signing keys are indexed by integers representing the step in the key's evolution. Since the private key evolves incrementally in a KES scheme, the ledger rules require the pool operators to evolve their keys every time a certain number of slots have passed. The details of when these keys are evolved are out of the scope of this document, and the reader is directed to the ledger spec.

Implementation and bindings

The Cardano compatible KES implementations are

The particular instantiation used in Cardano is of depth 6. An improvement on the representation of signatures is being worked on, and planned to be included in the next HF. This compact representation is available in both the Haskell library and the rust counterpart.

Note: The secret key representations of both libraries are not compatible. A padding strategy can be made to use Haskell generated data in Rust, but not vice-versa. To see this padding trick, you can look in the interoperability tests of the rust library.

Common mistakes

The main building block of KES is its underlying signature scheme, Ed25519. We refer the reader to the common mistakes section of Ed25519.

BIP32-ed25519

BIP32-ed25519 is an adaptation of the BIP32 proposal for deterministic key generation for the Ed25519 curve which has non-linear key space.

Implementation and bindings

We currently have two implementations of BIP32:

The preferred implementation is that of Rust, but both are safe to use.

For the C implementation, we have bindings in the following languages:

Common mistakes

As the underlying signature algorithm is ed25519, we refer the reader to common mistakes of that section.

ECDSA

ECDSA is one of signature schemes supported natively in Plutus, together with ed25519 and Schnorr. In particular, the natively supported ECDSA algorithm works over curve SECP256k1, enabling support for Bitcoin's and Ethereum's native signatures.

Implementation and bindings

We currently relly in Bitcoin's implementation available in secp256k1. We have analysed, and recommend, bindings in the following languages:

Common mistakes

An ECDSA signature consists of two values , where are scalars. A problem of using ECDSA in consensus critical contexts, is that the signature algorithm (as defined in the standard) is malleable. Specifically, given a valid signature , the tuple is also a valid signature. To avoid problems resulting from this malleability, the implementation we use checks that the , where is the order of the prime order group. More details of such a check in the spec section.

Another common problem of verifying ECDSA signatures is that the hashing of the message must be performed by the verifier itself, rather than accepting a hashed message. This can be dangerous. Therefore, the verifier, before proceeding with verification, hashes the message.

Schnorr

Schnorr is one of signature schemes supported natively in Plutus, together with ed25519 and ECDSA. In particular, the natively supported ECDSA algorithm works over curve SECP256k1, enabling support for Bitcoin's and Ethereum's native signatures. Schnorr signature scheme is also adopted by MuSig2 (Simple Two-Round Schnorr Multisignatures) which will be integrated to Hydra.

Implementation and binding

We currently relly in Bitcoin's implementation available in secp256k1. We have analysed, and recommend, bindings in the following languages:

MuSig2

This API also relies on secp256k1 that is compatible with BIP-340 producing 64-byte Schnorr signatures.

  • C: Available in musig2. Note that this API is still in progress.

VRF-ed25519

Verifiable Random Functions () allow key-pair owners, , to evaluate a pseudorandom function in a provable way given a randomness seed. Any party with access to the verification key, , the randomness seed, the proof and the generated randomness can indeed verify that the value is computed as expected. The VRF specification has changed overtime in Cardano, and the nodes use a different algorith, pre-Babbage and post-Babbage (if there exists a reference to the HF, we should point it out). We expose both specifications, and the motivations for such a change.

Implementation and bindings

We currently rely in the implementation available in the fork of libsodium. We have analysed, and recommend, bindings in the following languages:

Notation

In this section we introduce some generic notation used throughout the spec. The primitive-specific notation is introduced in the respective sections.

We denote by the finite abelian group based on an elliptic curve over a finite prime-order field (note that we simplify the notation and drop the explicit dependency on and security parameter ). Most importantly, we assume the order of the group to be of the form for some small cofactor (sometimes equal to 1) and large prime number , and that the (hence) unique (sub)group of order is generated by a known base point , i.e., , in which the computational Diffie-Hellman (CDH) problem is believed to be hard. We use to denote a cryptographically safe hash function, modeled as a random oracle, for any value of (we tried using but the katex compiler was not happy with it).

An elliptic curve point can be determined using the y-coordinate and the sign of the -coordinate, meaning that an elliptic curve point can be represented using bits. All elements in or are serialised in little-endian form. Elliptic curve points are encoded using their -coordinate followed by the sign bit of the coordinate. An element in is negative if the enconding of is lexicographically larger than the encoding of

Ed25519

Ed25519 is the signature scheme being used in Cardano, and supported in Plutus. Ed25519 is an instantiation of the EdDSA over the Edwards25519 elliptic curve.

Generalised specification

This section presents the generalized signature system EdDSA, and in the parameter section, we present the specific parameters used in Cardano. EdDSA is parametrized with the following parameters. An integer , a cryptographic hash function producing a -bit output, and a finite abelian group based on an elliptic curve. An EdDSA, signature consists of the following three algorithms:

  • takes as input the security parameter and returns a key-pair . First, it chooses . Next, let , and compute the signing key, . Finally, compute , and return .
  • takes as input a keypair and a message , and returns a signature . Let , and interpret the result as a little-endian integer in . Let , and . Return .
  • takes as input a message , a verification key and a signature , and returns depending on whether the signature is valid or not. The algorithm returns if the following equation holds and otherwise:

Parameters of instantiation

In this section we set to describe the concrete instantiation of the algorithm presented above. Not only we describe the Curves and Hash functions used, but we also specify how deserialization happens, as this results in important differences of the acceptance criteria of valid signatures. The algorithm we use is Ed255191. However, our implementation slightly differs in the deserialization criteria. The details are as follows:

  • Parameter : We set
  • Curve: We define the curve, and by consequence the finite prime order field, security parameter, cofactor, prime order subgroup and generator. In particular, we use Edwards25519 which is birationally equivalent to Curve255192.
  • Hash: As a hashing algorithm we use SHA512.
  • Deserialization: A signature is represented by 64 bytes: the first 32 bytes, , represent the point , and the final 32 bytes, , represent the scalar . A public key is also represented as 32 bytes, . Deserialization is valid only if:
    • , read as a little-endian integer, is smaller than .
    • does not represent a low order point (by checking against a precomputed blacklist of size ).
    • does not represent a low order point (by checking against a precomputed blacklist of size ), and when read as a little-endian integer, it is smaller than .
1

Bernstein, Duif, Lange, Schwabe and Yang, High-Speed High-Security Signatures

2

Bernstein, Curve25519: New Diffie-Hellman Speed Records

KES

In Cardano, nodes use Key Evolving Signatures (KES). This is another asymmetric key cryptographic scheme, also relying on the use of public and private key pairs. These signature schemes provide forward cryptographic security, meaning that a compromised key does not make it easier for an adversary to forge a signature that allegedly had been signed in the past.

In KES, the public verification key stays constant, but the corresponding private key evolves incrementally. For this reason, KES signing keys are indexed by integers representing the step in the key's evolution. Since the private key evolves incrementally in a KES scheme, the ledger rules require the pool operators to evolve their keys every time a certain number of slots have passed. The details of when these keys are evolved are out of the scope of this document, and the reader is directed to the ledger spec.

Generalised specification

We use the iterated sum construction from Section 4.3 of MMM1. A KES signature algorithm is parametrized by four algorithms, and . The sum construction depends on two signing algorithms, and , which are forward-secure with and time periods respectively. As specified in the paper, any digital signature algorithm can be considered as a forward-secure signature algorithm with 1 time period. We use two specialized versions of the key generation, one to generate the public part, and another to generate the secret part, respectively. The KES algorithm uses a length doubling pseudorandom generator, , where given a random seed, , returns two random seeds of the same size . The sum construction begins by generating a signing algorithm with two periods by merging two instances of the base signature, and proceeds recursively until the desired level of periods is reached.

The Chang hard fork will bring optimizations to the KES signature size, and we therefore have different verification criteria pre and post-Chang. Both instances use a tree of depth 6. For ease of exposure, we compare both constructions using a simple binary tree of depth 3 (see figure below). Consider each node as a KES instance with periods, where is the height of the node with respect to the leafs. For instance, A is a KES instance with periods, while node D is a KES instance with periods. Note that each KES instance is created by two child instances with half the periods. The only relevant details for compatibility on how KES algorithm works is signature generation and signature verification, however we provide a description of the other functions. The details on how the keys are managed are details of implementation which will not be covered here.

digraph keys {
  { 
     A, F, G, J, K, L, M, N, O, t [ shape = box, color = "black" ];
     B, D [ shape = box, color = "black", style = "filled", fillcolor = "green" ];
     C, E, H, I [ shape = box, color = "red", style = "filled", fillcolor = "green" ];
   };
   
   A -> B;
   A -> C;
   B -> D;
   B -> E;
   C -> F;
   C -> G;
   D -> H;
   D -> I;
   E -> J;
   E -> K;
   F -> L;
   F -> M;
   G -> N;
   G -> O;
   H -> t
}

In green, we have the nodes for which we need to store the public key in a signature during pre-babbage eras. With red borders we have the nodes for which we need to store the public keys in post-babbage eras.

Pre-Chang

The signing instances of nodes H-O are single period KES instances, and nodes A-G are defined by recursively calling on the algorithms presented above. In pre-Chang eras the signatures are computed in a naive manner, meaning that a signature is represented (recursively) as the underlying signature and the two public keys, . So for instance, the signature in node A of period 0 contains the signature of node B, , the public key of node B (which is a hash of and ) and the public key of node C (which is a hash of and ). Signature in turn contains signature of node D , the public key of node D (which is a hash of and ) and public key of node E (which is a hash of and ). The signature of node D, contains in turn the signature of node H, , the public key of node H, and the public key of node I . Verification of the signature works in the naive recursive manner. We check that , and , and , and finally that . More specifically:

  • takes as input a random seed. It then extends the seed into two parts, , and uses each seed to generate the key material of the next layer. In particular and . Finally, it computes the pair's public key and returns . \item takes as input a time period , a signing key and a message. If , then it computes the signature using the first signature algorithm, , otherwise it uses the other . Finally, returns .
  • takes as input a time period , and a signing key . If , then . Otherwise, it checks if its changing the key generation algorithm. Specifically, if , then and sets the seed to zero . Otherwise, .
  • takes as input a verification key, , a message, , a signature, , and a time period, . First, it checks that . If that is not the case, it returns . Otherwise, if then , else . If verification fails, it returns , otherwise it returns .

Post-Chang

The naive definition of the signature used in Pre-Chang results in poor performance with respect to the signature size. We don't need to verify the hash equality at each level, and we simply need to do so at the root. In the Chang hardfork we introduced such an optimization. In particular, instead of storing both public keys in each signature, we only store the one of the branch that we are not in. For the case of the KES instances with 1 period, the KES signature contains not only the underlying signature, but also the public key, which allows us to re-walk the merkle path. Again, assume we are in period 0. Then, the signature in node A of period 0 contains the signature of node B, , and the public key of node C (which is a hash of and ). Signature in turn contains signature of node D and public key of node E (which is a hash of and ). The signature of node D, contains in turn the signature of node H, , and the public key of node I . In this case, , where is the underlying signature. Verification of the signature works going up the tree, rather than down. We check . Then we compute the expected key of node D, . Then we use that to compute the expected key of node B, . Finally, we check that the leaf indeed is part of the merkle tree by checking that . To derive the missing public key, we introduce a new function, .

Specifically, post-Chang KES signature algorithm modifies the and algorithms, and introduces as follows:

  • takes as input a random seed. It then extends the seed into two parts, , and uses each seed to generate the key material of the next layer. In particular and . Finally, it computes the pair's public key and returns .
  • takes as input a time period , a signing key and a message. If , then it computes the signature using the first signature algorithm, and lets , otherwise it uses the other , and lets . Finally, returns .
  • takes as input a time period , and a signing key . If , then . Otherwise, it checks if its changing the key generation algorithm. Specifically, if , then and sets the seed to zero . Otherwise, .
  • takes as input a signature and a period . If , then and return , otherwise and return .
  • takes as input a verification key, , a message, , a signature, , and a time period, . First, it computes , and then, if , check that , otherwise, check that . If verification fails, it returns , otherwise it returns .

For this recursive explanation to be complete, we need to define what happens when we call on a leaf signature. Recall that the signature of a leaf contains not only the underlying signature, but also the public key with which it is signed. The derive function at the leaf takes as input . It proceeds by verifying the leaf signature. Parse , and compute the result . If , then return , else return .

Parameters of instantiation

The instantiation of both eras is the same. The underlying signature scheme is Ed25519. Regarding and , in Cardano, these functions simply call a seeded version of Ed25519's and extract the public or private part. As a hashing function we use Blake2b2. Defining the pseudo random function is not required for compatibility purposes, as it is only used for private key material. However, for sake of completeness, we specify that the cardano node uses Blake2b as a length doubling pseudorandom generator.

1

Malkin, Micciancio and Miner, Composition and Efficiency Tradeoffs for Forward-Secure Digital Signatures

2

Aumasson, The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)

ECDSA

ECDSA, together with Schnorr, were two new signature algorithms introduced in Plutus during Cardano's Valentine upgrade.

Generalised specification

This section presents the generalized signature system ECDSA, and in the parameter section, we present the specific parameters used in Cardano. ECDSA is parametrized with the following parameters. An ECDSA signature consists of the following three algorithms:

  • takes as input the security parameter and returns a key-pair . First, it chooses . Finally, compute , and return .
  • takes as input a keypair and a message , and returns a signature . Let . Compute and interpret the result as its two individual coordinates . Next, compute . If , generate a new and start over. Finally compute . If , generate a new and start over. Otherwise, return .
  • takes as input a message , a verification key and a signature , and returns depending on whether the signature is valid or not. The algorithm returns if the following conditions hold and otherwise:
    • and are between and .
    • Compute and . Compute , and ensure it is not equal to the point at infinity. Checks that .

Parameters of instantiation

The above is the standard definition, and in cardano we instantiate it over curve SECP256k1. However, such a signature algorithm enables malleability. Given a valid signature , if one sets , then the pair is also a valid signature, as a point and its negative share the same x-coordinate. This can be problematic in consensus critical contexts. To that end, we follow Bitcoin's modification of only accepting signatures with small values of , i.e. with .

The signatures generated using Haskell's bindings (see here) use hash function SHA256. However, Plutus built-in function takes as input the hashed message, meaning that the signer and verifier can agree which hash function to use in their protocol.

While we follow the verification criteria used in Bitcoin, we do not follow their serialisation convention, DER-encoding, which results in variable sized signatures up to 72 bytes (instead of the 64 byte encoding we describe in this document).

More precisely, the following is what is the specification used in the plutus built-in functions:

  • The verification key must correspond to the (x, y) coordinates of a point on the SECP256k1 curve, where x, y are unsigned integers in big-endian form.
  • The verification key must correspond to a result produced by secp256k1_ec_pubkey_serialize, when given a length argument of 33, and the SECP256K1_EC_COMPRESSED flag. This implies all of the following:
    • The verification key is 33 bytes long.
    • The first byte corresponds to the parity of the y coordinate; this is 0x02 if y is even, and 0x03 otherwise.
    • The remaining 32 bytes are the bytes of the x coordinate.
  • The input to verify must be a 32-byte hash of the message to be checked. We assume that the caller of verifyEcdsaSecp256k1Signature receives the message and hashes it, rather than accepting a hash directly: doing so can be dangerous. Typically, the hashing function used would be SHA256; however, this is not required, as only the length is checked.
  • The signature must correspond to two unsigned integers in big-endian form; henceforth r and s.
  • The signature must correspond to a result produced by secp256k1_ecdsa_serialize_compact. This implies all of the following:
    • The signature is 64 bytes long.
    • The first 32 bytes are the bytes of r.
    • The last 32 bytes are the bytes of s.
        ┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┓
        ┃ r <32 bytes> │ s <32 bytes>  ┃
        ┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┛
        <--------- signature ---------->
    

Schnorr

Schnorr, together with ECDSA, were two new signature algorithms introduced in Plutus during Cardano's Valentine upgrade. MuSig2 is a two-round multi-signature scheme will be integrated to Hydra.

Generalised specification

This section presents the generalized signature system ECDSA and MuSig2. In the [parameter] (#parameters-of-instantiation) section, we present the specific parameters used in Cardano and MuSig2 C implementation.

A Schnorr signature consists of the following three algorithms:

  • takes as input the security parameter and returns a key-pair . First, it chooses . Finally, compute , and return .
  • takes as input a keypair and a message , and returns a signature . Let . Compute , then compute , and finally compute . The signature is .
  • takes as input a message , a verification key and a signature , and returns depending on whether the signature is valid or not. The algorithm returns if

Let be the number of signers and be the number of nonces. A two-round multi-signature scheme MuSig2 that outputs an ordinary Schnorr signature includes the following steps:

  • takes as input the security parameter and returns a key-pair . First, it chooses . Finally, compute , and return .

  • takes as input the security parameter and returns key-pairs . First, it chooses the nonces . Finally, computes the commitments , and returns the list including tuples of nonces and commitments.

  • takes the list of public keys and the signer's public key, returns the aggregate public key and . First creates . Computes for . Finally, generates the aggregate public key by and the signer keeps her own .

  • takes the list of all signers' commitment lists, returns the list of aggregate commitments. .

  • takes as input the keypair of the signer, a message , aggregate public key, the list of commitments and the list of nonces of the signer. Returns a signature . First, creates . Computes and . The single signature is calculated as .

  • takes the list of all signers' single signatures and aggregate commitment, returns the aggregate signature where .

  • takes as input a message, aggregate verification key, aggregate signature, and aggregate commitment. Computes and accepts the signature if .

Parameters of instantiation

The above is the standard definition, and in cardano we instantiate it over curve SECP256k1. Moreover, we follow BIP-0340. The following are the two specifications of the above algorithm required for compatibility. Citing literally BIP-0340:

  • We use implicit Y coordinates. We encode an elliptic curve point with 32 bytes, and we implicitly choose the Y coordinate that is even[6].
  • We use tagged hashed of SHA256 for the challenge computation. More precisely, in order to compute H(R, vk, m), one computes SHA256(SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge") || R || vk || m).

More precisely, the following is what is the specification used in the plutus built-in functions:

  • The verification key must correspond to the (x, y) coordinates of a point on the SECP256k1 curve, where x, y are unsigned integers in big-endian form.
  • The verification key must correspond to a result produced by secp256k1_xonly_pubkey_serialize. This implies all of the following:
    • The verification key is 32 bytes long.
    • The bytes of the signature correspond to the x coordinate.
  • The input to verify is the message to be checked; this can be of any length, and can contain any bytes in any position.
  • The signature must correspond to a point R on the SECP256k1 curve, and an unsigned integer s in big-endian form.
  • The signature must follow the BIP-340 standard for encoding. This implies all the following:
    • The signature is 64 bytes long.
    • The first 32 bytes are the bytes of the x coordinate of R, as a big-endian unsigned integer.
    • The last 32 bytes are the bytes of s.
        ┏━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━┓
        ┃ R <32 bytes> │ s <32 bytes>  ┃
        ┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┛
        <--------- signature ---------->
    

VRF-ed25519

Verifiable Random Functions () allow key-pair owners, , to evaluate a pseudorandom function in a provable way given a randomness seed. Any party with access to the verification key, , the randomness seed, the proof and the generated randomness can indeed verify that the value is computed as expected. The VRF specification has changed overtime in Cardano, and the nodes use a different algorith, pre-Babbage and post-Babbage (if there exists a reference to the HF, we should point it out). We expose both specifications, and the motivations for such a change.

Generalised specification

We use an additional hash function to that introduced in the Notation section. In particular one that maps a binary input to an element of the group , .

Pre Babbage

A function, in pre-Babbage eras, is defined by the following three algorithms:

  • follows the exact same procedure as described in ed25519. Output key pair . We refer to the signing key in the Ed25519 section as .
  • takes as input a keypair and a message , and returns the randomness together with a proof . Use to derive . Let . Let . Compute as defined in procedure as in ed25519. Let . Compute . Finally, return the proof and the randomness .
  • takes as input a message , a verification key and a vrf proof , and returns or . It parses the proof as , and computes . Let and . Compute the challenge . If , then return , otherwise, return .

Post Babbage

A function, in post-Babbage eras, is defined by the following three algorithms:

  • follows the exact same procedure as described in ed25519. Output key pair . We refer to the signing key in the Ed25519 section as .
  • takes as input a keypair and a message , and returns the randomness together with a proof . Use to derive . Let . Let . Compute as defined in procedure as in ed25519. Let . Compute . Finally, return the proof and the randomness .
  • takes as input a message , a verification key and a vrf proof , and returns or . It parses the proof as , and computes . Next, compute . Finally, if and , then return , otherwise, return .

This change allows for batch verification of proofs, which achieve up to a times two improvement in verification time, in exchange of a larger proof.

Parameters of instantiation

Some of the concrete parameter instantiations also differ between pre-Babbage and post-Babbage eras. We begin by describing those which coincide, and follow with a separate description for the ones that differ.

  • Parameter and suite : We set . We choose the suite , as defined in the standard draft1. This sets the parameter as and the following parameters.
  • Curve: We define the curve, and by consequence the finite prime order field, security parameter, cofactor, prime order subgroup and generator, as described in the ed25519 paper2. In particular, we use Edwards25519 which is birationally equivalent to Curve25519.
  • Hash: As a hashing algorithm we use SHA512.

Pre Babbage

We proceed with the specifications on pre-Babbage eras.

  • Draft version: pre-Babbage eras are build on top of Version 03 of the standards draft3.
  • Deserialization: A proof is represented by 80 bytes: the first 32 bytes, , represent the point , the following 16 bytes, , represent the scalar , and the final 32 bytes, , represent the scalar . A public key is also represented as 32 bytes, . Deserialization is valid only if:
    • when read as a little-endian integer, it is smaller than .
    • does not represent a low order point (by checking against a precomputed blacklist of size , and when read as a little-endian integer, it is smaller than .
  • Hash to curve : Elligator mapping, over a scalar computed by hashing . The mechanism is described in Section~5.4.1.2 of version 3 of the draft. Note that for implementing the mechanism as described in the draft, the sign bit is cleared before calling the elligator function, meaning that the latter always works with sign = 0 (see function). See Appendix A.4 of version 3 of the draft for test vectors.

Post Babbage

We finalize with the specifications of post-Babbage eras.

  • Draft version: post-Babbage eras are build on top of a batch-compatible version of Version 10 of the standards draft4. The specific construction is described in the technical spec studying the security of batch compatibility5.
  • Deserialization: A proof is represented by 128 bytes: the first 32 bytes, , represent the point , the following 32 bytes, , represent the point , the following 32 bytes, , represent the point , and the final 32 bytes, , represent the scalar . A public key is also represented as 32 bytes, . Deserialization is valid only if:
    • when read as a little-endian integer, it is smaller than .
    • when read as a little-endian integer, is smaller than .
    • does not represent a low order point (by checking against a precomputed blacklist of size , and when read as a little-endian integer, it is smaller than .
  • Hash to curve : Hash to curve algorithm as defined in the hash to curve standard6, version 12, Section 6.8.2 (non uniform version). For test vectors, one can use those presented in Appendix J.5.2 of that same document. Reference implementation can be found in the libsodium fork.
1

Goldberg, Reyzin, Papadopoulos and Včelák, Verifiable Random Functions (VRFs); version 15

2

Bernstein, Duif, Lange, Schwabe and Yang, High-Speed High-Security Signatures

3

Goldberg, Reyzin, Papadopoulos and Včelák, Verifiable Random Functions (VRFs); version 03

5

Badertscher, Gazi, Querejeta-Azurmendi and Russell, On UC-Secure Range Extension and Batch Verification for ECVRF

6

Faz-Hernández, Scott, Sullivan, Wahby and Wood, Hashing to Elliptic Curves