7 - LLMQ Signing Requests / Sessions#
DIP: 0007 Title: LLMQ Signing Requests / Sessions Author(s): Alexander Block Special-Thanks: Cofresi, Darren Tapp, Thephez, Samuel Westrich Comments-Summary: No comments yet. Status: Final Type: Standard Created: 2018-09-07 License: MIT License
Table of Contents#
Abstract#
This DIP defines how signing requests and sessions are performed by activated DIP006 Long Living Masternode Quorums (LLMQs). A LLMQ is able to perform BLS threshold signing on arbitrary messages. If enough members have signed the same message, a valid recovered threshold signature can be created and propagated to the rest of the network. A successfully recovered threshold signature is strongly secure, as it is either created or not created with no in-between state that might result in different nodes seeing different/conflicting signing results.
Motivation#
We want to have a generalized method of signing arbitrary messages, which can be applied to all kinds of use cases. One use case is InstantSend, other use cases will come from new features in Evolution. We will only slightly handle InstantSend as an example in this DIP, more details can be found in the appropriate specialized DIPs.
All these use cases require unambiguous results from a signing request: It should either succeed or fail network-wide. It should not be possible to have two nodes in the network see conflicting messages with different valid signatures for the same request.
Prior work#
Signing request#
A signing request is identified by a deterministically calculable, unique id which we will refer to as requestId in the remainder of the document. It can, for example, be the hash of an InstantSend transaction’s input.
Initiation of a signing request happens independently per LLMQ member. When and how to initiate the request depends on the use case. For InstantSend, this would be directly after receiving and validating a transaction.
The message hash must be supplied along with the requestId. For InstantSend, the message hash would be the hash of the full transaction. The combination of quorumHash, requestId and message hash forms the signing session.
A signing request can only be initiated once and should never be performed multiple times by the same masternode. This in turn results in “one vote per member” on each individual signing request and makes it impossible to have conflicting recovered signatures for the same signing request.
As a result of a (non-conflicting) signing request, the member must create a threshold signature share. It does this by calculating SHA256(quorumHash, requestId, messageHash)
and then signing the resulting hash with the members individual threshold secret key share. After signing, the signature share must be propagated to all LLMQ members (explained later).
Signing session#
A signing session is identified by the LLMQ’s quorumHash, signing request id and the message hash. If any member of the LLMQ receives enough threshold signature shares for a signing session, it can create the final recovered threshold signature from these shares. This recovered signature is propagated to the whole network (including non-members) and can then be verified by all nodes based on the LLMQs quorum public key.
If different members signed the same request with differing message hashes, only one of the signing sessions will create enough signature shares to reach the threshold and thus only one valid recovered signature can be created. If not enough signature shares for the same signing session can be collected, no valid recovered threshold signature will be created. In the InstantSend use case, this would indicate a failed attempt to double spend transaction inputs.
Choosing the active LLMQ to perform signing#
As multiple LLMQs are active at the same time and masternodes might be members of multiple LLMQs as well, it’s important that all masternodes agree on which LLMQ should service the signing request. Otherwise it would be impossible to collect enough signature shares for the same signing session and thus recovery of the threshold signature would never succeed.
To calculate which LLMQ is responsible for a signing request, each masternode should perform the following:
Take the active LLMQ set from 8 blocks before the current chain tip. Active LLMQ sets are described in DIP6 - Long-Living Masternode Quorums section “Active LLMQ sets”.
For each LLMQ of the active set, calculate
SHA256(quorumType, quorumHash, requestId)
Sort the list of LLMQs based on the result of step 2 in ascending order.
Use the first entry of the sorted list as the LLMQ to perform the signing request
After the responsible LLMQ is determined, the masternode should check if it is part of the chosen LLMQ. If it is not part of that LLMQ, it must completely skip the signing request.
Validating recovered threshold signatures#
Each node (including regular nodes) must verify the recovered signatures for each signing session before accepting and relaying them. This can be done by validating the recovered signature and SHA256(quorumHash, requestId, messageHash)
against the LLMQ’s quorum public key.
If this succeeds, the signing request is considered successful. In the InstantSend example, this would mean that a single input of the transaction has been locked.
Internal high-level API#
Inside the Dash Core Node, we will implement a high-level API that can be leveraged by the individual use cases. The API will support the following operations:
void SignIfMember(uint256 id, uint256 msgHash, int activeLLMQs)#
Selects the correct LLMQ based on the last active LLMQs and performs the signing request if the caller is a member and only if it did not already sign another signing session for the same signing request.
void Sign(uint256 quorumHash, uint256 id, uint256 msgHash)#
Sign the given session if the caller is a member of the given quorum.
bool HasRecoveredSig(uint256 id, uint256 msgHash, int activeLLMQs)#
Returns true if a valid recovered threshold signature was received (or locally created) for the signing session and from the last active LLMQs. Please note that the activeLLMQs
parameter must not necessarily be the same value as was previously given to SignIfMember
. For some use cases it might be desirable to accept signatures from old/inactive LLMQs as well.
bool IsConflicting(uint256 id, uint256 msgHash)#
Returns true if any LLMQ created a valid recovered threshold signature for any signing session with a different message hash than the given one.
bool IsMajorityPossible(uint256 id, uint256 msgHash, int activeLLMQs)#
Returns true if a recovered signature has already been received (or locally created) or if it’s still possible for this to happen. This means, that it returns false if >= quorumThreshold
members have already signed a different signing session for the same request.
uint256 GetMostSignedSession(uint256 id, int activeLLMQs)#
Returns the msgHash
which was signed by most LLMQ members so far. Please note that the result is not final until HasRecoveredSig
returns true.
These operations will also be made available through RPC APIs so that external applications can also use the LLMQ signing capabilities. This will especially be useful for Evolution, as non-core services (L2) can then simply call these RPCs and won’t have to deal with the internals.
Copyright#
Copyright (c) 2018 Dash Core Group, Inc. Licensed under the MIT License