Documentation

Complexity.Crypto.Computational.MerkleSignature.Security

Security of Merkle signatures #

A forgery against MerkleSignature.scheme S H depth either contains a collision of H k, or it is a one-time forgery against S at the leaf it names. Two reductions turn this into a bound with an explicit loss, for every forger A and every security parameter n:

Pr[A forges] ≤ 2 ^ depth n * Pr[oneTimeForger A forges against S] + Pr[collisionFinder A finds a collision of H].

Merkle ([Mer90], Section 6) gives the construction with an informal argument. The bound is the composition, original to this library, of the plug-and-pray argument for indexed signatures from one-time signatures ([BS23], Section 14.6.1, referring to Exercise 13.2), the collision extraction behind [BS23], Theorem 8.8, for the shrunken public key, and the hash-and-sign bound of [BS23], Theorem 13.1, for the digest.

Main definitions #

Main results #

References #

The reduction to collision finding #

The candidate collision of H k in a forgery out = ((u, msg, sig), signed) against the keys keys: a collision in the tree if the forged verification key is not the one at leaf u, and otherwise the forged message with a message signed at leaf u with the same digest.

Instances For

    The collision finder: given the hash key k, generate the one-time keys, answer the forger's signing queries honestly, and return collisionOf its forgery.

    Instances For

      The reduction to one-time forgery #

      noncomputable def Cslib.Crypto.MerkleSignature.leafIndex (depth : ℕ → ℕ) (n : ℕ) :

      A uniform leaf below 2 ^ depth n, from depth n fair bits.

      Instances For
        noncomputable def Cslib.Crypto.MerkleSignature.plantKeys (S : SignatureScheme) (depth : ℕ → ℕ) (n i : ℕ) (vk : List Bool) :

        Sample a hash key and the one-time keys of every leaf except leaf i, where the verification key vk is planted with an empty secret key.

        Instances For

          The one-time forger's answer to a signing request: as the indexed signing oracle, except that leaf i is signed by an external query to the one-time signing oracle, whose reply is truncated to bound bits.

          Instances For
            noncomputable def Cslib.Crypto.MerkleSignature.oneTimeForgerAt (S : SignatureScheme) (H : List Bool → List Bool → List Bool) (depth bound : ℕ → ℕ) (adversary : IndexedForger) (i : ℕ) :

            The one-time forger with its challenge planted at leaf i.

            Instances For
              noncomputable def Cslib.Crypto.MerkleSignature.oneTimeForger (S : SignatureScheme) (H : List Bool → List Bool → List Bool) (depth bound : ℕ → ℕ) (adversary : IndexedForger) :

              The one-time forger: plant the challenge at a uniform leaf.

              Instances For

                Exact simulation by the one-time forger #

                The leaf is exactly uniform below 2 ^ depth n, the law of ProbComp.sampleBinaryNat (depth n) (ProbComp.eval_sampleBinaryNat). leafIndex reads its bits with BitString.boundedBinaryValue, whose cap 2 ^ depth n never binds, because the reduction needs the leaf in unary (isPPTOn_leafIndex), and Probability.isPPTOn_sampleBinaryNat outputs it in binary.

                The explicit bound #

                theorem Cslib.Crypto.MerkleSignature.succProbability_indexedEufCmaGame_le {S : SignatureScheme} {H : List Bool → List Bool → List Bool} {depth : ℕ → ℕ} (hH : Turing.MultiTapeTM.ComputableInPolyTime (fun (p : List Bool × List Bool) => H p.1 p.2) (Turing.MultiTapeTM.encPair Turing.MultiTapeTM.encBits Turing.MultiTapeTM.encBits) Turing.MultiTapeTM.encBits) (hlen : ∀ (k m : List Bool), (H k m).length = k.length) (hcap : Turing.MultiTapeTM.ComputableInPolyTime (fun (n : ℕ) => 2 ^ depth n) Turing.MultiTapeTM.encUnary Turing.MultiTapeTM.encUnary) {bound : ℕ → ℕ} {n : ℕ} (hbound : ∀ x ∈ (S.keyGen n).eval.support, ∀ (msg : List Bool), msg.length = n → ∀ σ ∈ (S.sign x.2 msg).eval.support, σ.length ≤ bound n) (adversary : IndexedForger) :
                Game.succProbability ((scheme S H depth hH hlen hcap).indexedEufCmaGame adversary n).eval ≤ 2 ^ depth n * Game.succProbability (S.eufOneTimeGame (oneTimeForger S H depth bound adversary) n).eval + Game.succProbability (collisionGame H (fun (x : ℕ) (x_1 : List Bool) => true) (collisionFinder S H depth hH hlen hcap adversary) n).eval

                Security of Merkle signatures, with an explicit loss. For every forger and every security parameter n, the forging probability against MerkleSignature.scheme S H depth is at most 2 ^ depth n times the success of oneTimeForger against S in the one-time game, plus the success of collisionFinder in the collision game of H. The bound bound n must cover the length of every one-time signature on an n-bit message under a supported key; the one-time forger truncates replies to it.

                Efficiency of the reductions #

                Security #

                Merkle signatures are secure ([Mer90], Section 6; [BS23], Section 14.6.1): if S is one-time EUF-CMA secure and H is collision resistant, then MerkleSignature.scheme S H depth is an indexed EUF-CMA secure signature scheme of capacity 2 ^ depth n. The reductions are oneTimeForger, with loss 2 ^ depth n, and collisionFinder, with loss 1 (succProbability_indexedEufCmaGame_le).

                Indexed signatures from one-way functions and collision-resistant hashing: Lamport's one-time scheme on any one-way function, under Merkle's tree with any collision-resistant hash family, gives an indexed EUF-CMA secure signature scheme of every polynomial capacity 2 ^ depth n.