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)