{"id":24020774,"url":"https://github.com/BlockstreamResearch/bip-frost-dkg","last_synced_at":"2025-09-14T20:32:06.601Z","repository":{"id":190699221,"uuid":"681353272","full_name":"BlockstreamResearch/bip-frost-dkg","owner":"BlockstreamResearch","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-08T07:40:00.000Z","size":927,"stargazers_count":61,"open_issues_count":17,"forks_count":18,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-08-07T07:31:41.534Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BlockstreamResearch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-08-21T20:35:53.000Z","updated_at":"2025-08-04T09:28:35.000Z","dependencies_parsed_at":"2023-10-30T10:30:09.858Z","dependency_job_id":"8532221f-0367-457b-916b-249a77fb59e2","html_url":"https://github.com/BlockstreamResearch/bip-frost-dkg","commit_stats":null,"previous_names":["jonasnick/bip-frost-dkg"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/BlockstreamResearch/bip-frost-dkg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlockstreamResearch%2Fbip-frost-dkg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlockstreamResearch%2Fbip-frost-dkg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlockstreamResearch%2Fbip-frost-dkg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlockstreamResearch%2Fbip-frost-dkg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BlockstreamResearch","download_url":"https://codeload.github.com/BlockstreamResearch/bip-frost-dkg/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlockstreamResearch%2Fbip-frost-dkg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275161864,"owners_count":25416077,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-14T02:00:10.474Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-08T12:18:25.651Z","updated_at":"2025-09-14T20:32:06.576Z","avatar_url":"https://github.com/BlockstreamResearch.png","language":"Python","funding_links":[],"categories":["Chronological Updates"],"sub_categories":[],"readme":"```\nBIP:\nTitle: ChillDKG: Distributed Key Generation for FROST\nAuthor: Tim Ruffing \u003ccrypto@timruffing.de\u003e\n        Jonas Nick \u003cjonas@n-ck.net\u003e\nStatus: Draft\nLicense: CC0-1.0\nLicense-Code: MIT\nType: Informational\nCreated:\nPost-History:\nComments-URI:\n```\n\n# ChillDKG: Distributed Key Generation for FROST\n\n### Abstract\n\nThis Bitcoin Improvement Proposal proposes ChillDKG, a distributed key generation protocol (DKG) for use with the FROST Schnorr threshold signature scheme.\n\n### Copyright\n\nThis document is made available under [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/).\nThe accompanying source code is licensed under the [MIT license](https://opensource.org/license/mit).\n\n## Introduction\n\n### Motivation\n\nThe FROST signature scheme [[KG20](https://eprint.iacr.org/2020/852), [CKM21](https://eprint.iacr.org/2021/1375), [BTZ21](https://eprint.iacr.org/2022/833), [CGRS23](https://eprint.iacr.org/2023/899)] enables `t`-of-`n` Schnorr threshold signatures,\nin which some threshold `t` of a group of `n` participants is required to produce a signature.\nFROST remains unforgeable as long as at most `t-1` participants are compromised\nand remain functional as long as `t` honest participants do not lose their secret key material.\nNotably, FROST can be made compatible with [BIP 340](bip-0340.mediawiki) Schnorr signatures and does not put any restrictions on the choice of `t` and `n` (as long as `1 \u003c= t \u003c= n`).[^t-edge-cases]\n\n[^t-edge-cases]: While `t = n` and `t = 1` are in principle supported, simpler alternatives are available in these cases.\nIn the case of `t = n`, using a dedicated `n`-of-`n` multi-signature scheme such as MuSig2 [[BIP 327](bip-0327.mediawiki)] instead of FROST avoids the need for an interactive DKG.\nThe case `t = 1` can be realized by letting one participant generate an ordinary [BIP 340](bip-0340.mediawiki) key pair and transmitting the key pair to every other participant, who can check its consistency and then simply use the ordinary [BIP 340](bip-0340.mediawiki) signing algorithm.\nParticipants still need to ensure that they agree on a key pair. A detailed specification is not in the scope of this document.\n\nAs a result, threshold signatures increase both security and availability,\nenabling users to escape the inherent dilemma between the contradicting goals of protecting a single secret key against theft and data loss simultaneously.\nBefore being able to create signatures, the participants need to generate a shared *threshold public key* (representing the entire group with its `t`-of-`n` policy),\ntogether with `n` corresponding *secret shares* (held by the `n` participants) that allow to sign under the threshold public key.\nThis key generation can, in principle, be performed by a trusted dealer who takes care of generating the threshold public key as well as all `n` secret shares,\nwhich are then distributed to the `n` participants via secure channels.\nHowever, the trusted dealer constitutes a single point of failure:\na compromised dealer can forge signatures arbitrarily.\n\nAn interactive *distributed key generation* (DKG) protocol session by all participants avoids the need for a trusted dealer.\nThere exist a number of DKG protocols with different requirements and guarantees in the cryptographic literature.\nMost suitable for the use with FROST is the PedPop DKG protocol [[KG20](https://eprint.iacr.org/2020/852), [CKM21](https://eprint.iacr.org/2021/1375), [CGRS23](https://eprint.iacr.org/2023/899)] (\"Pedersen DKG [[Ped92](https://doi.org/10.1007/3-540-46766-1_9), [GJKR07](https://doi.org/10.1007/s00145-006-0347-3)] with proofs of possession\"),\nwhich, like FROST, does not impose restrictions on the choice of `t` and `n`.\n\nBut similar to most DKG protocols in the literature, PedPop has strong requirements on the communication channels between participants,\nwhich make it difficult to deploy in practice:\nFirst, it assumes that participants have secure (i.e., authenticated and encrypted) channels between each other,\nwhich is necessary to avoid man-in-the-middle attacks and to ensure confidentiality of secret shares when delivering them to individual participants.\nSecond, PedPop assumes that all participants have access to some external consensus or reliable broadcast mechanism\nthat ensures they have an identical view of the protocol messages exchanged during DKG.\nThis will, in turn, ensure that all participants eventually reach agreement over the results of the DKG,\nwhich include not only parameters such as the generated threshold public key\nbut also whether the DKG has succeeded at all.\n\nTo understand the necessity of reaching agreement,\nconsider the example of a DKG to set up a 2-of-3 Bitcoin wallet\nin which two participants are honest but the third participant is malicious.\nThe malicious participant sends invalid secret shares to the first honest participant, but valid shares to the second honest participant.\nWhile the first honest participant cannot finish the DKG,\nthe second honest participant will believe that the DKG has finished successfully\nand thus may be willing to send funds to the resulting threshold public key.\nBut this constitutes a catastrophic failure:\nThose funds will be lost irrevocably because the single remaining secret share of the second participant will not be sufficient to produce a signature (without the help of the malicious participant).[^resharing-attack]\n\n[^resharing-attack]: A very similar attack has been observed in the implementation of a resharing scheme [[AS20](https://eprint.iacr.org/2020/1052), Section 3].\n\nTo sum up, there is currently no description of PedPop that\ndoes not assume the availability of external secure channels and consensus\nand thus can be turned into a standalone implementation.\nTo overcome these issues, we propose ChillDKG in this BIP.\nChillDKG is a variant of PedPop with \"batteries included\",\ni.e., it incorporates minimal but sufficient implementations of secure channels and consensus\nand thus does not have external dependencies.\nThis makes it easy to implement and deploy, and\nwe provide detailed algorithmic specifications in the form of Python code.\n\n### Design\n\nWe assume a network setup in which participants have point-to-point connections to an untrusted coordinator.\nThis will enable bandwidth optimizations and is common also in implementations of the signing stage of FROST.\nParticipants are identified and authenticated via long-term public keys.\n\nThe basic building block of ChillDKG is the SimplPedPop protocol (a simplified variant of PedPop),\nwhich has been designed specifically for FROST.\nSimplPedPop is proven to be secure when combined with FROST [[CGRS23](https://eprint.iacr.org/2023/899)],\nand its output contains, in addition to the threshold public key, separate per-participant public shares thereof,\nwhich allow for partial verification of contributions in a FROST signing session.\n\nBesides external secure channels, SimplPedPop depends on an external *equality check protocol*.\nThe equality check protocol serves as an abstraction of a consensus mechanism:\nIts only purpose is to check that, at the end of SimplPedPop, all participants have received identical protocol messages.\n\nOur goal is to turn SimplPedPop into a standalone DKG protocol without external dependencies.\nWe then follow a modular approach that removes one dependency at a time.\nFirst, we take care of secure channels by wrapping SimplPedPop in a protocol EncPedPop,\nwhich relies on pairwise ECDH key exchanges between the participants to encrypt secret shares.\nFinally, we add a concrete equality check protocol CertEq to EncPedPop to obtain a standalone DKG protocol ChillDKG.\n\nOur equality check protocol CertEq consists of every participant simply collecting a list of valid signatures on the session transcript from all `n` participants\nbefore finalizing the DKG session with some threshold public key as output.\nThe list of signatures, also called a *success certificate*, can convince any other honest participant\n(ultimately at the time of a signing request)\nthat the DKG session has indeed been successful.\nThis is sufficient to exclude the catastrophic failure described in the previous section.\n\nAs an additional feature of ChillDKG, the DKG outputs for any signing device can be fully recovered from\na backup of a single *host secret key* specific to the device,\n(the essential parts of) the public transcripts of the DKG sessions,\nand the corresponding success certificates.\nTo simplify the interface, we combine the transcript data and the session certificate into a single byte string called the *recovery data*,\nwhich is common to all participants and does not need to be kept confidential.\nRecovering a device that has participated in a DKG session then requires just the device's host secret key and the recovery data,\nthe latter of which can be obtained from any cooperative participant (or the coordinator) or from an untrusted backup provider.\n\nChillDKG outputs a threshold public key that can be safely used in Taproot outputs [[BIP 341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)].\nIn contrast, a standard PedPop implementation would allow a malicious participant to secretly embed a Taproot commitment to a script path within the threshold public key.\nIf such a key was used directly in a Taproot output, the malicious participant could spend the output through their hidden script path, bypassing the requirement for `t - 1` additional signatures.\nWhile [BIP 341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) outlines special precautions for using threshold public keys generated by standard PedPop, ChillDKG eliminates this vulnerability entirely, providing built-in protection against accidental misuse.\n\nIf a ChillDKG session fails due to the participants or the coordinator deviating from the protocol,\nany aborting party will be able to identify and blame a single party responsible for the failure\n(assuming the network, and, depending on the circumstances, the coordinator, is reliable).\n\nThese features make ChillDKG usable in a wide range of applications.\nAs a consequence of this broad applicability, there will necessarily be scenarios in which specialized protocols need less communication overhead and fewer rounds,\ne.g., when setting up multiple signing devices in a single location.\n\nIn summary, we aim for the following design goals:\n\n - **Standalone**: ChillDKG is fully specified, requiring no external secure channels or consensus mechanism.\n - **Conditional agreement**: If a ChillDKG session succeeds for one honest participant, this participant will be able to convince every other honest participant that the session has succeeded.\n - **No restriction on threshold**:  Like the FROST signing protocol, ChillDKG supports any threshold `t \u003c= n`, including `t \u003e n/2` (also called \"dishonest majority\").\n - **Broad applicability**:  ChillDKG supports a wide range of scenarios, from those where the signing devices are owned and connected by a single individual to those where multiple owners manage the devices from distinct locations.\n - **Simple backups**: ChillDKG allows recovering the DKG output using the host secret key and common recovery data shared among all participants and the coordinator. This eliminates the need for session-specific backups, simplifying user experience.\n - **Untrusted coordinator**: Like FROST, ChillDKG uses a coordinator that relays messages between the participants. This simplifies the network topology, and the coordinator additionally reduces communication overhead by aggregating some of the messages. A faulty coordinator can force the DKG to fail but cannot negatively affect the security of the DKG.\n - **Per-participant public shares**: ChillDKG supports partial signature verification in FROST signing sessions.\n - **Taproot-safe threshold public key**: ChillDKG prevents malicious participants from embedding a hidden Taproot commitment to a script path in the threshold public key.\n - **Blame functionality**: If a ChillDKG session aborts, it is possible to identify and blame a single party responsible for the failure (assuming the network, and, depending on the circumstances, the coordinator, is reliable).\n\nIn summary, ChillDKG incorporates solutions for both secure channels and consensus and simplifies backups in practice.\nAs a result, it fits a wide range of application scenarios,\nand due to its low overhead, we recommend ChillDKG even if secure communication channels or a consensus mechanism (e.g., a BFT protocol or a reliable broadcast mechanism) are readily available.\n\n#### Why Robustness is Not a Goal\n\nDespite the blame functionality, ChillDKG does not provide robustness, i.e., the protocol is not designed to succeed in the presence of faulty participants.\nIn fact, a single participant can cause the protocol to fail, either due to malicious intent, software bugs, or unreliable communication links.\nIn such cases, users must investigate and resolve the issue before the DKG can output key material.\n\nAdding robustness to ChillDKG would require the coordinator to exclude participants that appear unresponsive or faulty, which degrades the setup already from the beginning from `t`-of-`n` to `(t-1)`-of-`(n-1)`.\nThis approach is undesirable in most scenarios, as a faulty coordinator would have the power to exclude participants at will,\nand even if ChillDKG's design did not include a coordinator and participants had direct communication links to each other, it would be unclear how to achieve robustness in a dishonest majority setting.\n\nMoreover, we believe that it is preferable to err on the side of caution even in the case of benign failures.\nFor example, consider a key generation ceremony for a threshold cold wallet intended to store large amounts of Bitcoin.\nIf it turns out that one of the devices participating appears non-responsive, e.g., due to a loss of network or a software bug,\nusers will typically prefer security to progress, and abort the protocol instead of forcing successful termination of the ceremony by excluding the device from the DKG session.\nWhile warnings can be presented to users in this case, users tend to misunderstand and ignore them.\n\nEven in distributed systems with strict liveness requirements, e.g., a system run by a large federation of nodes of which a majority is trusted, what is typically necessary for the liveness of the system is the continued ability to *produce signatures*.\nHowever, the setup of keys is typically performed in a one-time ceremony at the inception of the system (and possibly repeated in large time intervals, e.g., every few months).\nIn other words, what is primarily required to ensure liveness in these applications is a robust signing protocol\n(and a solution for FROST exists [[RRJSS22](https://eprint.iacr.org/2022/550)]), and not a robust DKG protocol.\n\n### Structure of this Document\n\nDue to the complexity of ChillDKG, we do not provide both a pseudocode specification and a reference implementation.\nInstead, the BIP includes only a normative reference implementation in Python 3.12\n(see [`python/chilldkg_ref/chilldkg.py`](python/chilldkg_ref/chilldkg.py)),\nwhich serves as an executable specification.\n\nTo ease understanding of the design and reference code,\nwe provide a technical overview of the internals of ChillDKG in [Section \"Internals of ChillDKG\"](#internals-of-chilldkg).\nFor those who would like to use a ChillDKG implementation in their applications and systems,\nwe explain the external interface and usage considerations of ChillDKG in [Section \"Usage of ChillDKG\"](#usage-of-chilldkg).\n\n## Internals of ChillDKG\n\nThis section provides a detailed technical overview of the internals of ChillDKG,\nwhich includes as building blocks the DKG protocols SimplPedPop and EncPedPop, and the equality check protocol CertEq.\nThe contents of this section are purely informational and not strictly required to implement or use ChillDKG,\nand some details present in the normative Python reference implementation are omitted.\n\nWe stress that **this document does not endorse the direct use of SimplPedPop or EncPedPop as DKG protocols**.\nWhile SimplPedPop and EncPedPop may in principle serve as building blocks of other DKG protocols (e.g., for applications that already incorporate a consensus mechanism),\nthis requires careful further consideration, which is not in the scope of this document.\nConsequently, implementations should not expose the algorithms of the building blocks as part of a high-level API, which is intended to be safe to use.\n\n### DKG Protocol SimplPedPop\n\n(See [`python/chilldkg_ref/simplpedpop.py`](python/chilldkg_ref/simplpedpop.py).)\n\nThe SimplPedPop protocol has been proposed by Chu, Gerhart, Ruffing, and Schröder [Section 4, [CGRS23](https://eprint.iacr.org/2023/899)].\nWe make the following modifications as compared to the original SimplPedPop proposal:\n\n - Every participant holds a secret seed, from which all required random values are derived deterministically using a pseudorandom function (based on tagged hashes [[BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki)]).\n - Individual participants' public shares are added to the output of the DKG. This allows partial signature verification.\n - The participants send VSS commitments to an untrusted coordinator instead of directly to each other. This lets the coordinator aggregate VSS commitments, which reduces communication costs. Nevertheless, if a session fails, participants are able to investigate who provided invalid secret shares by asking the coordinator for the other participants' individual contributions to their public share.\n - To prevent a malicious participant from embedding a Taproot script path in the threshold public key, the participants tweak the VSS commitment such that the corresponding threshold public key has an unspendable script path.\n - ~The proofs of knowledge are not included in the data for the equality check. This will reduce the size of the backups in ChillDKG.~ (TODO: This will be fixed in an updated version of the paper.)\n\nOur variant of the SimplPedPop protocol then works as follows:\n\n1.  Every participant `i` (where `i` is an integer `0 \u003c= i \u003c n`) creates a `t`-of-`n` sharing of a random secret scalar using Feldman Verifiable Secret Sharing (VSS), a variant of Shamir Secret Sharing.\n    This involves generating random coefficients `a_i[0], ..., a_i[t-1]` of a polynomial `f_i` of degree `t-1` in the scalar group:\n\n    ```\n    f_i(Z) = a_i[0] + a_i[1] * Z + ... a_i[t-1] * Z^(t-1)\n    ```\n\n    Here, `f_i(0) = a_i[0]` acts as the secret scalar to be shared.\n    Participant `i` computes a VSS share `shares[j] = f_i(j+1)` for every participant `j` (including `j = i`),\n    which is supposed to be sent to participant `j` in private.\n    (This will be realized in EncPedPop using encryption.)\n\n    Participant `i` then sends a VSS commitment,\n    which is a vector `com = (com[0], ...,  com[t-1]) = (a_i[0] * G, ...,  a_i[t-1] * G)` of group elements,\n    where `G` is the base point of the secp256k1 elliptic curve,\n    and a BIP 340 Schnorr signature `pop` on message \"`i`\" with secret key `a_i[0]` to the coordinator.\n    (The Schnorr signature acts as a *proof of possession*,\n    i.e., it proves knowledge of the discrete logarithm of `com[0] = a_i[0] * G`.\n    This avoids rogue-key attacks, also known as key cancellation attacks.)\n\n2.  Upon receiving `coms[j] = (coms[j][0], ...,  coms[j][t-1])` and `pops[j]` from every participant `j`,\n    the coordinator aggregates the commitments\n    by computing the component-wise sum of all `coms[j]` vectors except for their first components `coms[j][0]`,\n    which are simply concatenated (because the participants will need them to verify the proofs of possession):\n\n    ```\n    sum_coms_to_nonconst_terms = (coms[0][1] + ... + coms[n-1][1], ..., coms[0][t-1] + ... + coms[n-1][t-1])\n    coms_to_secrets = (coms[0][0], ..., coms[n-1][0])\n    ```\n\n    The coordinator sends the vectors `coms_to_secrets`, `sum_coms_to_nonconst_terms`, and `pops` to every participant.\n\n3.  Upon receiving `coms_to_secrets`, `sum_coms_to_nonconst_terms`, and `pops` from the coordinator,\n    every participant `i` verifies every signature `pops[j]` using message `j` and public key `coms_to_secrets[j]`.\n    If any signature, say the one from participant `j`, is invalid, participant `i` aborts and blames participant `j` for the failure of the session.\n\n    Otherwise, i.e., if all signatures are valid, participant `i` sums the components of `coms_to_secrets`,\n    and prepends the sum to the `sum_coms_to_nonconst_terms` vector, resulting in a vector `sum_coms`.\n    (Assuming the coordinator performed its computations correctly,\n    the vector `sum_coms` is now the complete component-wise sum of the `coms[j]` vectors from every participant `j`.\n    It acts as a VSS commitment to the sum `f = f_0 + ... + f_{n-1}` of the polynomials of all participants.)\n\n    Participant `i` computes its public share `pubshare` as:\n    ```\n    pubshare = (i+1)^0 * sum_coms[0] + ... + (i+1)^(t-1) * sum_coms[t-1]\n    ```\n\n    Let `partial_secshares` be the vector of the VSS shares that participant `i` has privately obtained from each participant,\n    and let `secshare = partial_secshares[0] + ... + partial_secshares[n-1]` be the sum of the vector components.\n    Participant `i` checks the validity of `secshare` against `sum_coms`\n    by checking if the equation `secshare * G = pubshare` holds.\n    (`secshare` is supposed to be equal to `f(i+1)`.)\n\n    If the check fails, participant `i` aborts.\n    Assuming the coordinator is honest and has sent a correct `sums_coms` vector,\n    participant `i` knows that some participant contributed a wrong summand to `secshare`,\n    but participant `i` does not have sufficient information to single out and blame the faulty participant.\n    In this case, participant `i` can optionally investigate the error by asking the coordinator for the vector `partial_pubshares` defined as:\n    ```\n    partial_pubshares[j] = (i+1)^0 * coms[j][0] + ... + (i+1)^(t-1) * coms[j][t-1]\n    ```\n    With this vector at hand, participant `i` verifies each component of `partial_secshares` individually\n    by checking for which participant `j` the equation `partial_secshares[j] * G = partial_pubshares[j]` does not hold.\n    Participant `i` blames this participant `j` .\n\n    Otherwise, i.e., in the successful case that the equation `secshare * G = pubshare` holds, participant `i` proceeds as follows.\n    In order to obtain a threshold public key with an unspendable Taproot script path [[BIP 341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)],\n    participant `i` computes a Taproot tweak `tweak` for an unspendable script path,\n    and adds the point `tweak * G` to `sum_coms[0]`, resulting in a new VSS commitment called `sum_coms_tweaked`.\n    Participant `i` computes the public share of every participant as\n    ```\n    pubshares[j] = (j+1)^0 * sum_coms_tweaked[0] + ... + (j+1)^(t-1) * sum_coms_tweaked[t-1]\n    ```\n    Correspondingly, participant `i` computes `secshare_tweaked = secshare + tweak`.\n\n    Then, participant `i` sets the DKG output consisting of\n    this participant's secret share `secshare_tweaked`,\n    the threshold public key `threshold_pubkey = sum_coms_tweaked[0]`, and\n    all participants' public shares `pubshares`.\n\n    As a final step, participant `i` enters a session of an external equality check protocol\n    to verify that all participants agree on the *transcript*, i.e., common data produced during the session,\n    and that none of them has aborted the session due to an invalid VSS share or an invalid proof of possession.\n    The transcript of SimplPedPop, constructed in a variable `eq_input`,\n    is simply the concatenation (of serializations) of `t` and the `sum_coms` vector.\n    Upon the equality protocol returning successfully,\n    participant `i` returns successfully with the DKG outputs as computed above.\n    Details of the interface of the equality check protocol will be described further below in\n    [Subsection \"Background on Equality Checks\"](#background-on-equality-checks).\n\n### DKG Protocol EncPedPop\n\n(See [`python/chilldkg_ref/encpedpop.py`](python/chilldkg_ref/encpedpop.py).)\n\nEncPedPop is a thin wrapper around SimplPedPop that takes care of encrypting the VSS shares\nso that they can be sent over an insecure communication channel.\n\nAs in SimplPedPop, every EncPedPop participant holds a long-term secret seed.\nEvery participant derives from this seed a static, long-term ECDH key pair consisting of a secret decryption key and a public encryption key.\nIt is assumed that every participant has an authentic copy of every other participant's encryption key.\n\nThe encryption relies on ephemeral-static ECDH key exchange.\nEvery participant derives from fresh randomness an ephemeral encryption nonce pair consisting of a secret nonce and the corresponding public nonce.\nThis will enable every pair of sending participant `i` and recipient participant `j != i`\nto perform an ECDH key exchange between the ephemeral encryption nonce pair of participant `i` and the static encryption key pair of participant `j`\nin order to establish a shared secret pad `pad_ij` only known to participants `i` and `j`.\nThe derivation of `pad_ij` from the raw ECDH output uses a tagged hash and includes\nadditional context, namely the static encryption key and the index `j` of the recipient.[^mr-kem]\n\n[^mr-kem]: This implements a multi-recipient multi-key key encapsulation mechanism (MR-MK-KEM) secure under the static Diffie-Hellman assumption [[Theorem 2, PPS14](https://doi.org/10.1145/2590296.2590329)].\n\nWhen `j = i` (i.e., when a participant encrypts a VSS share for themselves), the computationally expensive ECDH key exchange is unnecessary.\nInstead, the participant repurposes the secret decryption key as a symmetric key, such that `pad_ii` is computed as the tagged hash of the decryption key, public encryption nonce, and context.\n\nEvery participant derives an ephemeral *session seed* passed down to SimplPedPop from their long-term seed and their public encryption nonce.\nMoreover, all encryption keys of all participants are included in the derivation to ensure that different sets of participants will have different SimplPedPop sessions,\neven in the case that the randomness for deriving the encryption nonce pair is accidentally reused.\n\nEncPedPop then works like SimplPedPop with the following differences:\nParticipant `i` will additionally transmit their public encryption nonce and an encrypted VSS share `shares[j] + pad_ij` for every other participant `j`\nas part of the first message to the coordinator.\nThe coordinator collects all encrypted VSS shares,\nand computes the sum `enc_secshare[i]` of all shares intended for every participant `i`.\nThe coordinator sends all public encryption nonces along with the sum `enc_secshare[i]` to participant `i`.\nParticipant `i` stores the sum as `enc_secshare`,\nderives the pads `pad_0i`, ..., `pad_ni` as described above,\nobtains the value `secshare = enc_secshare - (pad_0i + ... + pad_ni)`,\nand passes it down to SimplPedPop.\n\nIf SimplPedPop raises an error because this `secshare` value fails VSS verification,\nthen participant `i` can optionally investigate the error\nby asking the coordinator for the vector `enc_partial_secshares` of the individual contributions of all participants to `enc_secshare`.\nParticipant `i` obtains the vector `partial_secshares`, which SimplPedPop requires for investigating the error,\nby decrypting the components of `enc_partial_secshares` via `partial_secshares[j] = enc_partial_secshares[j] - pad_ji` for every other participant `j`.\nThen, participant `i` can pass `partial_secshares` down to SimplPedPop,\nwhich, after additionally obtaining the vector `partial_pubshares` from the coordinator,\nhas all the information required to determine and blame a faulty participant.\n\nOtherwise, i.e., if SimplPedPop does not raise an error,\nEncPedPop appends to the transcript `eq_input` of SimplPedPop the `n` public encryption nonces,\nand also all the `n` static encryption keys to ensure that the participants agree on their identities.\nThe inclusion of the latter excludes man-in-the-middle attacks if Eq authenticates participants,\ne.g, if the Eq protocol messages are signed under long-term public keys of the participants.\n\n### Background on Equality Checks\n\nAs explained in the \"Motivation\" section, it is crucial for security that participants reach agreement over the results of a DKG session.\nSimplPedPop, and consequently also EncPedPop, ensure agreement during the final step of the DKG session by running an external *equality check protocol* Eq.\nThe purpose of Eq is to verify that all participants have received an identical *transcript*, which is a byte string constructed by the respective DKG protocol.\n\nEq is assumed to be an interactive protocol between the `n` participants with the following abstract interface:\nEvery participant can invoke a session of Eq with an input value `eq_input`.\nEq may not return at all to the calling participant,\nbut if it returns successfully to some participant, then all honest participants agree on the value `eq_input`.\n(However, it may be the case that not all honest participants have established this fact yet.)\nThis means that the DKG session was successful, and the resulting threshold public key can be returned to the participant,\nwho can use it, e.g., by sending funds to some Bitcoin address derived from it.\n\nMore formally, Eq must fulfill the following properties [[CGRS23](https://eprint.iacr.org/2023/899)]:\n - **Integrity:** If Eq returns successfully to some honest participant, then for every pair of input values `eq_input` and `eq_input'` provided by two honest participants, we have `eq_input = eq_input'`.\n - **Conditional Agreement:** Assuming all messages are delivered eventually, if Eq returns successfully to some honest participant, then Eq will eventually return successfully to all honest participants.\n\nDepending on the application scenario, different approaches may be suitable to implement Eq,\nsuch as a consensus protocol already available as part of a federated system\nor out-of-band communication.\nFor example, in a scenario where a single user employs multiple signing devices to set up a threshold wallet,\nevery device could display its value `eq_input` (or a hash of `eq_input` under a collision-resistant hash function) to the user.\nThe user could manually verify the equality of the values by comparing the values shown on all displays,\nand confirm their equality by providing explicit confirmation to every device, e.g., by pressing a button on every device.\nSimilarly, if signing devices are controlled by different organizations in different geographic locations,\nagents of these organizations could meet and compare the values.\nA detailed treatment of these out-of-band methods is out of scope of this document.\n\n### DKG Protocol ChillDKG\n\n(See [`python/chilldkg_ref/chilldkg.py`](python/chilldkg_ref/chilldkg.py).)\n\nInstead of performing an out-of-band check as the last step of the DKG,\nChillDKG relies on a more direct approach:\nIt is a wrapper around EncPedPop,\nwhich instantiates the required equality check protocol with a concrete in-band protocol CertEq.\nCertEq assumes that each participant holds a long-term key pair of a signature scheme, called the *host key pair*.\nChillDKG repurposes the host key pairs as the ECDH key pairs required by EncPedPop,[^joint-security]\nand it repurposes the host secret key as the seed required by EncPedPop.\n\n[^joint-security]: Schnorr signatures and ECDH-based KEMs are known to be jointly secure [Theorem 2, [DLPSS11](https://eprint.iacr.org/2011/615)]\nunder the combination of the gap-DH and gap-DL assumptions, and this result can be adapted to the MR-KEM used in EncPedPop.\n\nChillDKG requires that all participants have authentic copies of the other participants' host public keys.[^trust-anchor]\nAuthenticity of the host public keys can be verified through pairwise out-of-band comparisons between every pair of participants.\nThis verification can occur at any time before the DKG session is finalized, in particular before the start of the session.\n\n[^trust-anchor]: No protocol can prevent man-in-the-middle attacks without this or a comparable assumption.\nNote that this requirement is implicit in other schemes as well.\nFor example, setting up a multi-signature wallet via non-interactive key aggregation in MuSig2 [[BIP 327](bip-0327.mediawiki)]\nalso requires the assumption that all participants have authentic copies of each other's individual public keys.\n\n#### Equality Check Protocol CertEq\n\nThe CertEq protocol is straightforward:[^certeq-literature]\nEvery participant sends a signature on their input value `eq_input` to every other participant (via the untrusted coordinator),\nand expects to receive valid signatures on `eq_input` from the other participants.\nA participant terminates successfully as soon as the participant has collected what we call a *success certificate*,\ni.e., a full list of valid signatures from all `n` participants (including themselves).[^multisig-cert]\n\n[^multisig-cert]: Abstractly, the required primitive is a multi-signature scheme, i.e., `n` participants signing the same message `eq_input`.\nWe have chosen the naive scheme of collecting a list of `n` individual signatures for simplicity.\nOther multi-signatures schemes,\ne.g., MuSig2 [[BIP 327](bip-0327.mediawiki)] or a scheme based on Schnorr signature half aggregation [[Halfagg-BIP-Draft](https://github.com/BlockstreamResearch/cross-input-aggregation/blob/master/half-aggregation.mediawiki), [CGKN21](https://eprint.iacr.org/2021/350), [CZ22](https://eprint.iacr.org/2022/222)],\ncould be used instead to reduce the size of the success certificate.\nThese methods are out of scope of this document.\n\n[^certeq-literature]: CertEq can be viewed as a signed variant of the Goldwasser-Lindell echo broadcast protocol [[GL05](https://eprint.iacr.org/2002/040), Protocol 1], or alternatively, as a unanimous variant of Signed Echo Broadcast [[Rei94](https://doi.org/10.1145/191177.191194), Section 4], [[CGR11](https://doi.org/10.1007/978-3-642-15260-3), Algorithm 3.17].)\n\nThis termination rule immediately implies the integrity property:\nUnless a signature has been forged, if some honest participant with input `eq_input` terminates successfully,\nthen by construction, all other honest participants have sent a signature on `eq_input` and thus received `eq_input` as input.\n\nThe key insight to ensuring conditional agreement is that any participant terminating successfully\nobtains a *success certificate* `cert` consisting of the collected list of all `n` signatures on `eq_input`.\nThis certificate will, by the above termination rule, convince every other honest participant (who, by integrity, has received `eq_input` as input) to terminate successfully.\nCrucially, this other honest participant will be convinced even after having received invalid or no signatures during the actual run of CertEq,\ndue to unreliable networks, a faulty coordinator, or faulty participants signing more than one value.\n\nThus, the certificate does not need to be sent during a normal run of CertEq,\nbut can instead be presented to other participants later,\ne.g., during a request to participate in a FROST signing session.\n\n#### Facilitating Backup and Recovery\n\nChillDKG constructs a transcript `eq_input` by appending to the transcript of EncPedPop the vector `enc_secshare`.\nThis ensures that all participants agree on all encrypted shares,\nand as a consequence,\nthe entire DKG output of a successful ChillDKG participant can be deterministically reproduced from a per-participant *host secret key* and the transcript.\n\nThis property is leveraged to offer a backup and recovery functionality:\nChillDKG outputs a string called *recovery data* which is the concatenation of the transcript `eq_input` and the success certificate `cert`.\nThe recovery data, which is the same for every participant, can be used by any participant together with the host secret key to recover the full output of the DKG session.\n\nCrucially, the recovery data carries proof that the DKG session took place:\nany recovering participant can extract their own valid signature on the transcript from the success certificate.\nThis valid signature proves that the participant, or more precisely, their former instance,\nhad successfully reached the state at which this signature is sent to the coordinator.\nIn particular, this implies that the proofs of possession from all participants,\nwhich are omitted in recovery data for succinctness,\nhad been checked successfully.\n\nIn fact, the recovery procedure subsumes the handling of a valid success certificate\nwhich is presented to the participant only after the session\n(in case an invalid or no certificate was received during the session).\nAs a result, ChillDKG does not provide a dedicated method for providing a success certificate after the session,\nand callers can simply use the recovery functionality instead.\n\n## Usage of ChillDKG\n\nThe purpose of this section is to provide a high-level overview of the interface and usage of ChillDKG,\naimed at developers who would like to use a ChillDKG implementation in their applications and systems.\n\nDetailed API documentation of the reference implementation is provided in [Subsection \"API Documentation\"](#api-documentation).\nDevelopers who would like to implement ChillDKG or understand ChillDKG's internals and reference implementation\nshould also read [Section \"Internals of ChillDKG\"](#internals-of-chilldkg).\n\n### Use ChillDKG only for FROST\n\nChillDKG is designed for usage with the FROST Schnorr signature scheme,\nand its security depends on the specifics of FROST.\nWe stress that ChillDKG is not a general-purpose DKG protocol,[^no-simulatable-dkg]\nand **must not** be combined with other threshold cryptographic schemes,\ne.g., threshold signature schemes other than FROST, or threshold decryption schemes,\nwithout careful further consideration, which is not in the scope of this document.\n\n[^no-simulatable-dkg]: As a variant of Pedersen DKG, ChillDKG does not provide simulation-based security [GJKR07](https://doi.org/10.1007/s00145-006-0347-3). Roughly speaking, if ChillDKG is combined with some threshold cryptographic scheme, the security of the combination is not automatically implied by the security of the two components. Instead, the security of every combination must be analyzed separately. The security of the specific combination of SimplPedPop (as the core building block of ChillDKG) and FROST has been analyzed [CGRS23](https://eprint.iacr.org/2023/899).\n\n### Protocol Parties and Network Setup\n\nThere are `n \u003e= 2` *participants*, `t` of which will be required to produce a signature.\nEach participant has a point-to-point communication link to the *coordinator*\n(but participants do not have direct communication links to each other).\n\nIf there is no dedicated coordinator, one of the participants can act as the coordinator.\n\nEach participant and the coordinator, and the communication links may either be *honest*, i.e., reliable and adhering to the protocol, or *faulty*, i.e., controlled by an attacker or unreliable (e.g., due to software bugs).\n\n### Inputs and Output\n\nThe inputs of a session consist of a long-term *host secret key* (individual to each participant, not provided by the coordinator) and public *session parameters* (common to all participants and the coordinator).\n\nIf a session ChillDKG returns an output to a participant or the coordinator,\nthen we say that this party *deems the protocol session successful*.\nIn that case, the DKG output is a triple consisting of a *secret share* for participating in FROST signing sessions (individual to each participant, not returned to the coordinator), the *threshold public key* representing the `t`-of-`n` policy of the group (common to all participants and the coordinator), and a list of `n` *public shares* for verification of individual contributions to a FROST signing session (common to all participants and the coordinator).\nMoreover, all parties obtain *recovery data* (common to all participants and the coordinator), whose purpose is detailed in the next subsection.\n\nTo participate in the FROST signing protocol, signers need their DKG output and their index in the host public key list, although the full list of host public keys is not required for signing.\nAdditionally, the set of indices of all participating signers within the host public key list is required to initiate a signing session.\n\n### Backup and Recovery\n\nLosing the secret share or the threshold public key, e.g., after the loss of a participant device, will render the participant incapable of participating in signing sessions.\nAs these values depend on the contributions of the other participants to the DKG session, they can,\nunlike deterministically derived secret keys [[BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)] as typically used for single-signer Schnorr signatures [[BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki)] or MuSig [[BIP 327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)],\nnot be rederived solely from the participant's seed.\n\nTo facilitate backups of a DKG session,\nChillDKG offers the possibility to recover a participant's DKG output from the participant's host secret key and the recovery data of the specific session,\nAs a result, a full backup of a participant consists of the host secret key as well as the recovery data of all DKG sessions the participant has successfully participated in.\n\nSince the recovery data is the same for all participants,\nif a participant loses the backup of the recovery data of the DKG session,\nthey can request it from any other participants or the coordinator.\nMoreover, the recovery data contains secrets only in encrypted form and is self-authenticating\nso that it can, in principle, be stored with an untrusted third-party backup provider.\n\nUsers **should** be aware that the session parameters (the threshold and the host public keys) and public parts of the DKG output (the threshold public key and the public shares) can be inferred from the recovery data, which may constitute a privacy issue.\nTo eliminate this issue, users can encrypt the recovery data using an encryption key derived from their host secret key before publishing the data.\nRecovery from encrypted data requires only the participant's host secret key, with no additional secrets needed.\nThis BIP does not specify the encryption scheme.\n\nKeeping backups of the secret key accessible and secure is hard (typically similarly hard as keeping the participant devices themselves).\nAs a consequence, it may not be an unreasonable strategy in a threshold setup not to perform backups of host secret keys at all,\nand simply hope that `t` honest and working participants will remain available.\nAs soon as one or more participants are lost or broken, a new DKG session can be performed with the lost participants replaced.\nThe obvious drawback of this method is that it will result in a change of the threshold public key,\nand the application will, therefore, need to transition to the new threshold public key,\ne.g., funds stored under the current threshold public key need to be transferred to the new key.\n\nWhether to perform backups of host secret keys and how to manage them ultimately depends on the requirements of the application,\nand we believe that a general recommendation is not useful.\n\n### Recovering Stuck Parties\n\nThe mere fact that a protocol party deems a ChillDKG session successful does not imply that other parties deem it successful yet.\nIndeed, due to failing communication links or invalid messages sent by faulty parties,\nit is possible that one party has deemed the DKG session successful, but others have not (yet) and thus are stuck in the DKG session.\nIn that case, the successful parties can eventually convince the stuck parties to consider the DKG session successful by presenting the recovery data to them.\nThe recovery data can, e.g., be attached to the first request to initiate a FROST signing session.\n\nAn important implication of the above is that anyone who uses the threshold public key,\nand thereby relies on the participants' ability to participate in signing sessions,\n**must** ensure that the participants have already deemed the DKG session successful,\nor at least, that the recovery data will be available to convince any stuck participants of the success of the DKG session.\n\nFor an example of what could go wrong,\nassume that some participant deems the DKG session successful and uses the threshold public key by sending funds to some Bitcoin address derived from it.\nEven though everything looks fine from the perspective of this participant,\nit is entirely possible that this participant is the only one who has deemed the DKG session successful,\nand thus (besides the untrusted coordinator) the only one who knows the recovery data.\nIf the recovery data is lost now because this participant's permanent storage fails,\nthe other participants cannot be convinced to deem the DKG session successful\n(without the help of the untrusted coordinator)\nand so the funds will be lost.\n\nThus, anyone who intends to use the threshold public key\n**should** first obtain explicit confirmations from all participants that they have deemed the DKG session successful,\nwhich will also imply that all participants have a redundant copy of the recovery data.\nOne simple method of obtaining confirmation is to collect signed confirmation messages from all participants.\n\nDepending on the application, other methods may be appropriate.\nFor example, in a scenario where a single user employs multiple signing devices in the same room to set up a threshold wallet,\nthe user could check that all `n` devices signal confirmation via its display.\nAlternatively, the user could check all `n` devices when generating a receiving address for the first time,\nwhich constitutes the first use of the threshold public key.\n\nIf a recovering party (see [Backup and Recovery](#backup-and-recovery)) cannot (re-)obtain confirmations,\nthis simply means they **should** stop using the threshold public key going forward,\ne.g., stop sending additional funds to addresses derived from it.\n(But, in contrast to the bad example laid out above,\nit will still be possible to spend the funds,\nand even recovered participants can participate in signing sessions.)\n\n### Blaming Faulty Parties\n\nAny faulty party can make a ChillDKG session abort by sending a message that deviates from the protocol specification.\nTo help resolve the underlying problem, ChillDKG provides a *blame functionality*\nthat enables honest protocol parties to identify and blame at least one participant suspected to be faulty:\n - If an honest participant aborts the session, then this participant will blame at least one participant or the coordinator.\n - If an honest coordinator aborts the session, then the coordinator then will blame at least one participant.\n\nMoreover, a party which, instead of aborting after having received an invalid protocol message,\naborts due to a timeout while waiting for a protocol message\nwill trivially blame the party who is supposed to send the outstanding message.\n\nThe guarantees provided by the blame functionality are limited,\nand its primary purpose is to support manual investigation and debugging efforts.\nDifferent parties, even if honest, are not guaranteed to blame the same party,\nand there is, in general, no way to verify an accusation by some party that another party is to blame.\nNevertheless, if all messages in the ChillDKG session have been transmitted correctly over the communication links,\nand, in case of a participant blaming another participant, if the coordinator is additionally honest,\nthe aborting party will be guaranteed that the blamed party is indeed faulty.\n\nIt is important to understand that this guarantee is conditional.\nFor example, assume that the condition of a honest coordinator is violated.\nIn that case, even if all participants are honest, the malicious coordinator can deviate from the protocol in a way that makes one participant blame another participant, when, in fact, it is the coordinator who is faulty and not the blamed participant.\n\nIn some cases,[^incorrect-shares] an aborting participant needs to obtain an auxiliary *investigation message* from the coordinator\nin order to single out and blame another participant (see [Overview of a ChillDKG session](#overview-of-a-chilldkg-session)).\n\n[^incorrect-shares]: Namely, when having received incorrect secret shares.\n\n### Threat Model and Security Goals\n\nWe expect ChillDKG to provide the following informal security goals when it is used to set up keys for the FROST threshold signature scheme.\nIf a participant deems a protocol session successful (as defined in [Inputs and Outputs](#inputs-and-outputs)), then this participant is assured that:\n - A coalition of at most `t - 1` faulty participants and a faulty coordinator cannot forge a signature under the returned threshold public key on any message `m` for which no signing session with at least one honest participant was initiated. (Unforgeability)[^unforgeability-formal]\n - All honest participants who deem the protocol session successful will have correct and consistent protocol outputs.\n   In particular, they agree on the threshold public key, the list of public shares, and the recovery data.\n   Moreover, any `t` of them have secret shares consistent with the threshold public key.[^correctness-formal]\n   This means that any `t` participants have all the necessary inputs to run FROST signing sessions which produce signatures valid under the threshold public key.\n - The success certificate will, when presented to any other (honest) participant, convince that other participant to deem the protocol successful.\n\n[^unforgeability-formal]: See Chu, Gerhart, Ruffing, and Schröder [Definition 3, [CGRS23](https://eprint.iacr.org/2023/899)] for a formal definition.\n\n[^correctness-formal]: See Ruffing, Ronge, Jin, Schneider-Bensch, and Schröder [Definition 2.5, [RRJSS22](https://eprint.iacr.org/2022/550)] for a formal definition.\n\n### Overview of a ChillDKG Session\n\n(See also [`python/example.py`](python/example.py).)\n\nThe following figure shows an example ChillDKG involving the participants and the coordinator.\nFor simplicity, only one participant is depicted.\nArrows indicate network messages between the parties.\nEach message sent by the coordinator is a broadcast message,\ni.e., the coordinator sends the same message to each participant.[^no-reliable-broadcast]\nUnless participants abort due to errors, all participants run the same code and send messages in the same steps.\n\n[^no-reliable-broadcast]: Recall that we do not assume a *reliable* broadcast channel but instead that the coordinator has separate a point-to-point communication links to each participant. In other words, the protocol prescribes that an honest coordinator sends the same message to every participant, but the security of the protocol does not depend on the coordinator adhering to that prescribe.\n\nTODO Add on-wire messages sizes to the figure after defining message serialization format.\n\n![The figure shows the message flow between a participant and a coordinator.\nThe first of two phases named \"Generation of host public keys\" involves the participant invoking the hostpubkey_gen function with parameter hostseckey and sending the returned hostpubkey to the coordinator.\nThe second phase named \"Session\" is initiated by the coordinator sending hostpubkeys and the threshold t to the participant.\nThe participant invokes participant_step1 and sends the returned pmsg1 to the coordinator.\nThe coordinator invokes coordinator_step1 and sends the returned cmsg1 to the participant.\nThe participant invokes participant_step2 and sends the returned pmsg2 to the coordinator.\nThe coordinator invokes coordinator_finalize and sends the returned cmsg2 to the participant.\nThe participant invokes participant_finalize, which ends the second phase.\n](images/chilldkg-sequence.png \"ChillDKG\")\n\nA participant can run multiple sessions with the same hostseckey, provided that the session state as output from any of the \"step\" functions is not reused.\nMultiple sessions may be run concurrently.\n\nWhenever an invoked function fails and raises an error, the corresponding party will abort the session and,\nin most cases, blame a participant or the coordinator for the failure of the session.\nHowever, if a participant aborts during the `participant_step2` function,\nthere may be insufficient information determine another participant to blame.\nIn this case, an optional *investigation procedure* is available:\nThe aborting participant can ask the coordinator for an auxiliary *investigation message* (generated via the `coordinator_investigate` function),\nwhich will allow the participant to blame a specific other participant (via the `participant_investigate` function).\n\nApplications may choose to let the coordinator always create and send investigation messages,\n(i.e., even if not asked for by an aborting participant).\nWhile different aborting participants will need different investigation messages,\nan investigation message intended for some participant does not to be kept confidential from other participants.\nThus, applications may additionally choose to let the coordinator send all `n` investigation messages to all `n` participants.\n\n### API Documentation\n\nThis subsection is an export of the API documentation generated from the docstrings in the reference implementation\n(see [`python/chilldkg_ref/chilldkg.py`](python/chilldkg_ref/chilldkg.py).)\n\n\u003c!--pydoc.md--\u003e\n#### hostpubkey\\_gen\n\n```python\ndef hostpubkey_gen(hostseckey: bytes) -\u003e bytes\n```\n\nCompute the participant's host public key from the host secret key.\n\nThe host public key is the long-term cryptographic identity of the\nparticipant.\n\nThis function interprets `hostseckey` as big-endian integer, and computes\nthe corresponding \"plain\" public key in compressed serialization (33 bytes,\nstarting with 0x02 or 0x03). This is the key generation procedure\ntraditionally used in Bitcoin, e.g., for ECDSA. In other words, this\nfunction is equivalent to `IndividualPubkey` as defined in\n[[BIP 327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki#key-generation-of-an-individual-signer)].\nTODO Refer to the FROST signing BIP instead, once that one has a number.\n\n*Arguments*:\n\n- `hostseckey` - This participant's long-term secret key (32 bytes).\n  The key **must** be 32 bytes of cryptographically secure randomness\n  with sufficient entropy to be unpredictable. All outputs of a\n  successful participant in a session can be recovered from (a backup\n  of) the key and per-session recovery data.\n\n  The same host secret key (and thus the same host public key) can be\n  used in multiple DKG sessions. A host public key can be correlated\n  to the threshold public key resulting from a DKG session only by\n  parties who observed the session, namely the participants, the\n  coordinator (and any eavesdropper).\n\n\n*Returns*:\n\n  The host public key (33 bytes).\n\n\n*Raises*:\n\n- `HostSeckeyError` - If the length of `hostseckey` is not 32 bytes or if the\n  key is invalid.\n\n#### HostSeckeyError Exception\n\n```python\nclass HostSeckeyError(ValueError)\n```\n\nRaised if the host secret key is invalid.\n\nThis incluces the case that its length is not 32 bytes.\n\n#### SessionParams Tuples\n\n```python\nclass SessionParams(NamedTuple):\n    hostpubkeys: List[bytes]\n    t: int\n```\n\nA `SessionParams` tuple holds the common parameters of a DKG session.\n\n*Attributes*:\n\n- `hostpubkeys` - Ordered list of the host public keys of all participants.\n- `t` - The participation threshold `t`.\n  This is the number of participants that will be required to sign.\n  It must hold that `1 \u003c= t \u003c= len(hostpubkeys) \u003c= 2**32 - 1`.\n\n  Participants **must** ensure that they have obtained authentic host\n  public keys of all the other participants in the session to make\n  sure that they run the DKG and generate a threshold public key with\n  the intended set of participants. This is analogous to traditional\n  threshold signatures (known as \"multisig\" in the Bitcoin community),\n  [[BIP 383](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki)],\n  where the participants need to obtain authentic extended public keys\n  (\"xpubs\") from the other participants to generate multisig\n  addresses, or MuSig2\n  [[BIP 327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)],\n  where the participants need to obtain authentic individual public\n  keys of the other participants to generate an aggregated public key.\n\n  A DKG session will fail if the participants and the coordinator in a session\n  don't have the `hostpubkeys` in the same order. This will make sure that\n  honest participants agree on the order as part of the session, which is\n  useful if the order carries an implicit meaning in the application (e.g., if\n  the first `t` participants are the primary participants for signing and the\n  others are fallback participants). If there is no canonical order of the\n  participants in the application, the caller can sort the list of host public\n  keys with the [KeySort algorithm specified in\n  BIP 327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki#key-sorting)\n  to abstract away from the order.\n\n#### params\\_id\n\n```python\ndef params_id(params: SessionParams) -\u003e bytes\n```\n\nReturn the parameters ID, a unique representation of the `SessionParams`.\n\nIn the common scenario that the participants obtain host public keys from\nthe other participants over channels that do not provide end-to-end\nauthentication of the sending participant (e.g., if the participants simply\nsend their unauthenticated host public keys to the coordinator, who is\nsupposed to relay them to all participants), the parameters ID serves as a\nconvenient way to perform an out-of-band comparison of all host public keys.\nIt is a collision-resistant cryptographic hash of the `SessionParams`\ntuple. As a result, if all participants have obtained an identical\nparameters ID (as can be verified out-of-band), then they all agree on all\nhost public keys and the threshold `t`, and in particular, all participants\nhave obtained authentic public host keys.\n\n*Returns*:\n\n- `bytes` - The parameters ID, a 32-byte string.\n\n\n*Raises*:\n\n- `InvalidHostPubkeyError` - If `hostpubkeys` contains an invalid public key.\n- `DuplicateHostPubkeyError` - If `hostpubkeys` contains duplicates.\n- `ThresholdOrCountError` - If `1 \u003c= t \u003c= len(hostpubkeys) \u003c= 2**32 - 1` does\n  not hold.\n\n#### SessionParamsError Exception\n\n```python\nclass SessionParamsError(ValueError)\n```\n\nBase exception for invalid `SessionParams` tuples.\n\n#### DuplicateHostPubkeyError Exception\n\n```python\nclass DuplicateHostPubkeyError(SessionParamsError)\n```\n\nRaised if two participants have identical host public keys.\n\nThis exception is raised when two participants have an identical host public\nkey in the `SessionParams` tuple. Assuming the host public keys in question\nhave been transmitted correctly, this exception implies that at least one of\nthe two participants is faulty (because duplicates occur only with\nnegligible probability if keys are generated honestly).\n\n*Attributes*:\n\n- `participant1` _int_ - Index of the first participant.\n- `participant2` _int_ - Index of the second participant.\n\n#### InvalidHostPubkeyError Exception\n\n```python\nclass InvalidHostPubkeyError(SessionParamsError)\n```\n\nRaised if a host public key is invalid.\n\nThis exception is raised when a host public key in the `SessionParams` tuple\nis not a valid public key in compressed serialization. Assuming the host\npublic keys in question has been transmitted correctly, this exception\nimplies that the corresponding participant is faulty.\n\n*Attributes*:\n\n- `participant` _int_ - Index of the participant.\n\n#### ThresholdOrCountError Exception\n\n```python\nclass ThresholdOrCountError(SessionParamsError)\n```\n\nRaised if `1 \u003c= t \u003c= len(hostpubkeys) \u003c= 2**32 - 1` does not hold.\n\n#### DKGOutput Tuples\n\n```python\nclass DKGOutput(NamedTuple):\n    secshare: Optional[bytes]\n    threshold_pubkey: bytes\n    pubshares: List[bytes]\n```\n\nHolds the outputs of a DKG session.\n\n*Attributes*:\n\n- `secshare` - Secret share of the participant (or `None` for coordinator)\n- `threshold_pubkey` - Generated threshold public key representing the group\n- `pubshares` - Public shares of the participants\n\n#### participant\\_step1\n\n```python\ndef participant_step1(hostseckey: bytes, params: SessionParams, random: bytes) -\u003e Tuple[ParticipantState1, ParticipantMsg1]\n```\n\nPerform a participant's first step of a ChillDKG session.\n\n*Arguments*:\n\n- `hostseckey` - Participant's long-term host secret key (32 bytes).\n- `params` - Common session parameters.\n- `random` - FRESH random byte string (32 bytes).\n\n\n*Returns*:\n\n- `ParticipantState1` - The participant's session state after this step, to\n  be passed as an argument to `participant_step2`. The state **must\n  not** be reused (i.e., it must be passed only to one\n  `participant_step2` call).\n- `ParticipantMsg1` - The first message to be sent to the coordinator.\n\n\n*Raises*:\n\n- `HostSeckeyError` - If the length of `hostseckey` is not 32 bytes, if the\n  key is invalid, or if the key does not match any entry of\n  `hostpubkeys`.\n- `InvalidHostPubkeyError` - If `hostpubkeys` contains an invalid public key.\n- `DuplicateHostPubkeyError` - If `hostpubkeys` contains duplicates.\n- `ThresholdOrCountError` - If `1 \u003c= t \u003c= len(hostpubkeys) \u003c= 2**32 - 1` does\n  not hold.\n- `RandomnessError` - If the length of `random` is not 32 bytes.\n\n#### RandomnessError Exception\n\n```python\nclass RandomnessError(ValueError)\n```\n\nRaised if the length of the provided randomness is not 32 bytes.\n\n#### participant\\_step2\n\n```python\ndef participant_step2(hostseckey: bytes, state1: ParticipantState1, cmsg1: CoordinatorMsg1) -\u003e Tuple[ParticipantState2, ParticipantMsg2]\n```\n\nPerform a participant's second step of a ChillDKG session.\n\n*Warning:*\nAfter sending the returned message to the coordinator, this participant\n**must not** erase the hostseckey, even if this participant does not receive\nthe coordinator reply needed for the `participant_finalize` call. The\nunderlying reason is that some other participant may receive the coordinator\nreply, deem the DKG session successful and use the resulting threshold\npublic key (e.g., by sending funds to it). If the coordinator reply remains\nmissing, that other participant can, at any point in the future, convince\nthis participant of the success of the DKG session by presenting recovery\ndata, from which this participant can recover the DKG output using the\n`recover` function.\n\n*Arguments*:\n\n- `hostseckey` - Participant's long-term host secret key (32 bytes).\n- `state1` - The participant's session state as output by\n  `participant_step1`.\n- `cmsg1` - The first message received from the coordinator.\n\n\n*Returns*:\n\n- `ParticipantState2` - The participant's session state after this step, to\n  be passed as an argument to `participant_finalize`. The state **must\n  not** be reused (i.e., it must be passed only to one\n  `participant_finalize` call).\n- `ParticipantMsg2` - The second message to be sent to the coordinator.\n\n\n*Raises*:\n\n- `HostSeckeyError` - If the length of `hostseckey` is not 32 bytes.\n- `FaultyCoordinatorError` - If the coordinator is faulty. See the\n  documentation of the exception for further details.\n- `FaultyParticipantOrCoordinatorError` - If another known participant or the\n  coordinator is faulty. See the documentation of the exception for\n  further details.\n- `UnknownFaultyParticipantOrCoordinatorError` - If another unknown\n  participant or the coordinator is faulty, but running the optional\n  investigation procedure of the protocol is necessary to determine a\n  suspected participant. See the documentation of the exception for\n  further details.\n\n#### participant\\_finalize\n\n```python\ndef participant_finalize(state2: ParticipantState2, cmsg2: CoordinatorMsg2) -\u003e Tuple[DKGOutput, RecoveryData]\n```\n\nPerform a participant's final step of a ChillDKG session.\n\nIf this function returns properly (without an exception), then this\nparticipant deems the DKG session successful. It is, however, possible that\nother participants have received a `cmsg2` from the coordinator that made\nthem raise an exception instead, or that they have not received a `cmsg2`\nfrom the coordinator at all. These participants can, at any point in time in\nthe future (e.g., when initiating a signing session), be convinced to deem\nthe session successful by presenting the recovery data to them, from which\nthey can recover the DKG outputs using the `recover` function.\n\n*Warning:*\nChanging perspectives, this implies that, even when obtaining an exception,\nthis participant **must not** conclude that the DKG session has failed, and\nas a consequence, this particiant **must not** erase the hostseckey. The\nunderlying reason is that some other participant may deem the DKG session\nsuccessful and use the resulting threshold public key (e.g., by sending\nfunds to it). That other participant can, at any point in the future,\nconvince this participant of the success of the DKG session by presenting\nrecovery data to this participant.\n\n*Arguments*:\n\n- `state2` - The participant's state as output by `participant_step2`.\n- `cmsg2` - The second message received from the coordinator.\n\n\n*Returns*:\n\n- `DKGOutput` - The DKG output.\n- `bytes` - The serialized recovery data.\n\n\n*Raises*:\n\n- `FaultyParticipantOrCoordinatorError` - If another known participant or the\n  coordinator is faulty. Make sure to read the above warning, and see\n  the documentation of the exception for further details.\n- `FaultyCoordinatorError` - If the coordinator is faulty. Make sure to read\n  the above warning, and see the documentation of the exception for\n  further details.\n\n#### participant\\_investigate\n\n```python\ndef participant_investigate(error: UnknownFaultyParticipantOrCoordinatorError, cinv: CoordinatorInvestigationMsg) -\u003e NoReturn\n```\n\nInvestigate who is to blame for a failed ChillDKG session.\n\nThis function can optionally be called when `participant_step2` raises\n`UnknownFaultyParticipantOrCoordinatorError`. It narrows down the suspected\nfaulty parties by analyzing the investigation message provided by the coordinator.\n\nThis function does not return normally. Instead, it raises one of two\nexceptions.\n\n*Arguments*:\n\n- `error` - `UnknownFaultyParticipantOrCoordinatorError` raised by\n  `participant_step2`.\n- `cinv` - Coordinator investigation message for this participant as output\n  by `coordinator_investigate`.\n\n\n*Raises*:\n\n- `FaultyParticipantOrCoordinatorError` - If another known participant or the\n  coordinator is faulty. See the documentation of the exception for\n  further details.\n- `FaultyCoordinatorError` - If the coordinator is faulty. See the\n  documentation of the exception for further details.\n\n#### coordinator\\_step1\n\n```python\ndef coordinator_step1(pmsgs1: List[ParticipantMsg1], params: SessionParams) -\u003e Tuple[CoordinatorState, CoordinatorMsg1]\n```\n\nPerform the coordinator's first step of a ChillDKG session.\n\n*Arguments*:\n\n- `pmsgs1` - List of first messages received from the participants. The\n  list's length must equal the total number of participants.\n- `params` - Common session parameters.\n\n\n*Returns*:\n\n- `CoordinatorState` - The coordinator's session state after this step, to be\n  passed as an argument to `coordinator_finalize`. The state is not\n  supposed to be reused (i.e., it should be passed only to one\n  `coordinator_finalize` call).\n- `CoordinatorMsg1` - The first message to be sent to all participants.\n\n\n*Raises*:\n\n- `InvalidHostPubkeyError` - If `hostpubkeys` contains an invalid public key.\n- `DuplicateHostPubkeyError` - If `hostpubkeys` contains duplicates.\n- `ThresholdOrCountError` - If `1 \u003c= t \u003c= len(hostpubkeys) \u003c= 2**32 - 1` does\n  not hold.\n- `FaultyParticipantError` - If another participant is faulty. See the\n  documentation of the exception for further details.\n\n#### coordinator\\_finalize\n\n```python\ndef coordinator_finalize(state: CoordinatorState, pmsgs2: List[ParticipantMsg2]) -\u003e Tuple[CoordinatorMsg2, DKGOutput, RecoveryData]\n```\n\nPerform the coordinator's final step of a ChillDKG session.\n\nIf this function returns properly (without an exception), then the\ncoordinator deems the DKG session successful. The returned `CoordinatorMsg2`\nis supposed to be sent to all participants, who are supposed to pass it as\ninput to the `participant_finalize` function. It is, however, possible that\nsome participants pass a wrong and invalid message to `participant_finalize`\n(e.g., because the message is transmitted incorrectly). These participants\ncan, at any point in time in the future (e.g., when initiating a signing\nsession), be convinced to deem the session successful by presenting the\nrecovery data to them, from which they can recover the DKG outputs using the\n`recover` function.\n\nIf this function raises an exception, then the DKG session was not\nsuccessful from the perspective of the coordinator. In this case, it is, in\nprinciple, possible to recover the DKG outputs of the coordinator using the\nrecovery data from a successful participant, should one exist. Any such\nsuccessful participant is either faulty, or has received messages from\nother participants via a communication channel beside the coordinator.\n\n*Arguments*:\n\n- `state` - The coordinator's session state as output by `coordinator_step1`.\n- `pmsgs2` - List of second messages received from the participants. The\n  list's length must equal the total number of participants.\n\n\n*Returns*:\n\n- `CoordinatorMsg2` - The second message to be sent to all participants.\n- `DKGOutput` - The DKG output. Since the coordinator does not have a secret\n  share, the DKG output will have the `secshare` field set to `None`.\n- `bytes` - The serialized recovery data.\n\n\n*Raises*:\n\n- `FaultyParticipantError` - If another participant is faulty. See the\n  documentation of the exception for further details.\n\n#### coordinator\\_investigate\n\n```python\ndef coordinator_investigate(pmsgs: List[ParticipantMsg1]) -\u003e List[CoordinatorInvestigationMsg]\n```\n\nGenerate investigation messages for a ChillDKG session.\n\nThe investigation messages will allow the participants to investigate who is\nto blame for a failed ChillDKG session (see `participant_investigate`).\n\nEach message is intended for a single participant but can be safely\nbroadcast to all participants because the messages contain no confidential\ninformation.\n\n*Arguments*:\n\n- `pmsgs` - List of first messages received from the participants.\n\n\n*Returns*:\n\n- `List[CoordinatorInvestigationMsg]` - A list of investigation messages, each\n  intended for a single participant.\n\n#### recover\n\n```python\ndef recover(hostseckey: Optional[bytes], recovery_data: RecoveryData) -\u003e Tuple[DKGOutput, SessionParams]\n```\n\nRecover the DKG output of a ChillDKG session.\n\nThis function serves two different purposes:\n1. To recover from an exception in `participant_finalize` or\n`coordinator_finalize`, after obtaining the recovery data from another\nparticipant or the coordinator. See `participant_finalize` and\n`coordinator_finalize` for background.\n2. To reproduce the DKG outputs on a new device, e.g., to recover from a\nbackup after data loss.\n\n*Arguments*:\n\n- `hostseckey` - This participant's long-term host secret key (32 bytes) or\n  `None` if recovering the coordinator.\n- `recovery_data` - Recovery data from a successful session.\n\n\n*Returns*:\n\n- `DKGOutput` - The recovered DKG output.\n- `SessionParams` - The common parameters of the recovered session.\n\n\n*Raises*:\n\n- `HostSeckeyError` - If the length of `hostseckey` is not 32 bytes, if the\n  key is invalid, or if the key does not match the recovery data.\n  (This can also occur if the recovery data is invalid.)\n- `RecoveryDataError` - If recovery failed due to invalid recovery data.\n\n#### RecoveryDataError Exception\n\n```python\nclass RecoveryDataError(ValueError)\n```\n\nRaised if the recovery data is invalid.\n\n#### ProtocolError Exception\n\n```python\nclass ProtocolError(Exception)\n```\n\nBase exception for errors caused by received protocol messages.\n\n#### FaultyParticipantError Exception\n\n```python\nclass FaultyParticipantError(ProtocolError)\n```\n\nRaised if a participant is faulty.\n\nThis exception is raised by the coordinator code when it detects faulty\nbehavior by a participant, i.e., a participant has deviated from the\nprotocol. The index of the participant is provided as part of the exception.\nAssuming protocol messages have been transmitted correctly and the\ncoordinator itself is not faulty, this exception implies that the\nparticipant is indeed faulty.\n\nThis exception is raised only by the coordinator code. Some faulty behavior\nby participants will be detected by the other participants instead.\nSee `FaultyParticipantOrCoordinatorError` for details.\n\n*Attributes*:\n\n- `participant` _int_ - Index of the faulty participant.\n\n#### FaultyParticipantOrCoordinatorError Exception\n\n```python\nclass FaultyParticipantOrCoordinatorError(ProtocolError)\n```\n\nRaised if another known participant or the coordinator is faulty.\n\nThis exception is raised by the participant code when it detects what looks\nlike faulty behavior by a suspected participant. The index of the suspected\nparticipant is provided as part of the exception.\n\nImportantly, this exception is not proof that the suspected participant is\nindeed faulty. It is instead possible that the coordinator has deviated from\nthe protocol in a way that makes it look as if the suspected participant has\ndeviated from the protocol. In other words, assuming messages have been\ntransmitted correctly and the raising participant is not faulty, this\nexception implies that\n- the suspected participant is faulty,\n- *or* the coordinator is faulty (and has framed the suspected\nparticipant).\n\nThis exception is raised only by the participant code. Some faulty behavior\nby participants will be detected by the coordinator instead. See\n`FaultyParticipantError` for details.\n\n*Attributes*:\n\n- `participant` _int_ - Index of the suspected participant.\n\n#### FaultyCoordinatorError Exception\n\n```python\nclass FaultyCoordinatorError(ProtocolError)\n```\n\nRaised if the coordinator is faulty.\n\nThis exception is raised by the participant code when it detects faulty\nbehavior by the coordinator, i.e., the coordinator has deviated from the\nprotocol. Assuming protocol messages have been transmitted correctly and the\nraising participant is not faulty, this exception implies that the\ncoordinator is indeed faulty.\n\n#### UnknownFaultyParticipantOrCoordinatorError Exception\n\n```python\nclass UnknownFaultyParticipantOrCoordinatorError(ProtocolError)\n```\n\nRaised if another unknown participant or the coordinator is faulty.\n\nThis exception is raised by the participant code when it detects what looks\nlike faulty behavior by some other participant, but there is insufficient\ninformation to determine which participant should be suspected.\n\nTo determine a suspected participant, the raising participant may choose to\nrun the optional investigation procedure of the protocol, which requires\nobtaining an investigation message from the coordinator. See the\n`participant_investigate` function for details.\n\nThis is only raised for specific faulty behavior by another participant\nwhich cannot be attributed to another participant without further help of\nthe coordinator (namely, sending invalid encrypted secret shares).\n\n*Attributes*:\n\n- `inv_data` - Information required to perform the investigation.\n\u003c!--end of pydoc.md--\u003e\n\n## Changelog\n\nTo help the reader understand updates to this document, we attach a version number that resembles \"semantic versioning\" (`MAJOR.MINOR.PATCH`).\nThe `MAJOR` version is incremented if changes to the BIP are introduced that are incompatible with prior versions.\nAn exception to this rule is `MAJOR` version zero (0.y.z) which is for development and does not need to be incremented if backwards-incompatible changes are introduced.\nThe `MINOR` version is incremented whenever the inputs or the output of an algorithm changes in a backward-compatible way or new backward-compatible functionality is added.\nThe `PATCH` version is incremented for other noteworthy changes (bug fixes, test vectors, important clarifications, etc.).\n\n* *0.2.0* (2024-12-19): In addition to various readability improvements to specification and reference implementation, the following major changes were implemented:\n  * Fix security vulnerability where the CertEq signature did not cover the entire message.\n  * Add blame functionality to identify faulty parties, including an investigation phase.\n  * Make threshold public key Taproot-safe by default.\n  * Let each participant encrypt the secret share intended for themselves so that it can be decrypted instead of re-derived during recovery. The encryption is symmetric to avoid the overhead of an ECDH computation.\n* *0.1.0* (2024-07-08): Publication of draft BIP on the bitcoin-dev mailing list\n\n## Acknowledgments\n\nWe thank Lloyd Fournier (LLFourn) and Sivaram (siv2r) for their comments and contributions to this document.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBlockstreamResearch%2Fbip-frost-dkg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBlockstreamResearch%2Fbip-frost-dkg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBlockstreamResearch%2Fbip-frost-dkg/lists"}