********************** PoET 1.0 Specification ********************** Introduction ============ The Proof of Elapsed Time (PoET) Consensus method offers a solution to the Byzantine Generals Problem that utilizes a “trusted execution environment” to improve on the efficiency of present solutions such as Proof-of-Work. The initial reference implementation of PoET released to Hyperledger was written for an abstract TEE to keep it flexible to any TEE implementation. This specification defines a concrete implementation for SGX. The following presentation assumes the use of Intel SGX as the trusted execution environment. At a high-level, PoET stochastically elects individual peers to execute requests at a given target rate. Individual peers sample an exponentially distributed random variable and wait for an amount of time dictated by the sample. The peer with the smallest sample wins the election. Cheating is prevented through the use of a trusted execution environment, identity verification and blacklisting based on asymmetric key cryptography, and an additional set of election policies. For the purpose of achieving distributed consensus efficiently, a good lottery function has several characteristics: * Fairness: The function should distribute leader election across the broadest possible population of participants. * Investment: The cost of controlling the leader election process should be proportional to the value gained from it. * Verification: It should be relatively simple for all participants to verify that the leader was legitimately selected. PoET is designed to achieve these goals using new secure CPU instructions which are becoming widely available in consumer and enterprise processors. PoET uses these features to ensure the safety and randomness of the leader election process without requiring the costly investment of power and specialized hardware inherent in most “proof” algorithms. Sawtooth includes an implementation which simulates the secure instructions. This should make it easier for the community to work with the software but also forgoes Byzantine fault tolerance. PoET essentially works as follows: #. Every validator requests a wait time from an enclave (a trusted function). #. The validator with the shortest wait time for a particular transaction block is elected the leader. #. One function, such as “CreateTimer”, creates a timer for a transaction block that is guaranteed to have been created by the enclave. #. Another function, such as “CheckTimer”, verifies that the timer was created by the enclave. If the timer has expired, this function creates an attestation that can be used to verify that validator did wait the allotted time before claiming the leadership role. The PoET leader election algorithm meets the criteria for a good lottery algorithm. It randomly distributes leadership election across the entire population of validators with distribution that is similar to what is provided by other lottery algorithms. The probability of election is proportional to the resources contributed (in this case, resources are general purpose processors with a trusted execution environment). An attestation of execution provides information for verifying that the certificate was created within the enclave (and that the validator waited the allotted time). Further, the low cost of participation increases the likelihood that the population of validators will be large, increasing the robustness of the consensus algorithm. Definitions =========== The following terms are used throughout the PoET spec and are defined here for reference. Enclave A protected area in an application’s address space which provides confidentiality and integrity even in the presence of privileged malware. The term can also be used to refer to a specific enclave that has been initialized with a specific code and data. Basename A service provider base name. In our context the service provider entity is the distributed ledger network. Each distinct network should have its own Basename and Service Provider ID (see EPID and IAS specifications). EPID An anonymous credential system. See E. Brickell and Jiangtao Li: “Enhanced Privacy ID from Bilinear Pairing for Hardware Authentication and Attestation”. IEEE International Conference on Social Computing / IEEE International Conference on Privacy, Security, Risk and Trust. 2010. EPID Pseudonym Pseudonym of an SGX platform used in linkable quotes. It is part of the IAS attestation response according to IAS API specifications. It is computed as a function of the service Basename (validator network in our case) and the device's EPID private key. PPK, PSK PoET ECC public and private key created by the PoET enclave. IAS Report Key IAS public key used to sign attestation reports as specified in the current IAS API Guide. PSEmanifest Platform Services Enclave manifest. It is part of an SGX quote for enclaves using Platform Services like Trusted Time and Monotonic Counters. AEP Attestation evidence payload sent to IAS (see IAS API specifications). Contains JSON encodings of the quote, an optional PSEmanifest, and an optional nonce. AVR Attestation verification report, the response to a quote attestation request from the IAS. It is verified with the IAS Report Key. It contains a copy of the input AEP. :math:`WaitCertId_{n}` The :math:`n`-th or most recent WaitCertificate digest. We assume :math:`n >= 0` represents the current number of blocks in the ledger. WaitCertId is a function of the contents of the Wait Certificate. For instance the SHA256 digest of the WaitCertificate ECDSA signature. OPK, OSK Originator ECDSA public and private key. These are the higher level ECDSA keys a validator uses to sign messages. OPKhash SHA256 digest of OPK blockDigest ECDSA signature with OSK of SHA256 digest of transaction block that the validator wants to commit. localMean Estimated wait time local mean. MCID SGX Monotonic Counter identifier. SealKey The SGX enclave Seal Key. It is used by the SGX ``sgx_seal_data()`` and ``sgx_unseal_data()`` functions. PoetSealKey The Poet SGX enclave Seal Key. It must be obtained through the SGX SDK ```sgx_get_key()`` function passing a fixed 32 byte constant as ``key_id`` argument. PoET\_MRENCLAVE Public MRENCLAVE (see SGX SDK documentation) value of valid PoET SGX enclave. :math:`T_{WT}` WaitTimer timeout in seconds. A validator has at most :math:`T_{WT}` seconds to consume a WaitTimer, namely obtain a WaitCertificate on it after the WaitTimer itself has expired. :math:`K` Number of blocks a validator can commit before having to sign-up with a fresh PPK. :math:`c` The "sign-up delay", i.e., number of blocks a validator has to wait after sign-up before starting to participate in elections. minDuration Minimum duration for a WaitTimer. P2P PoET SGX Enclave Specifications =================================== The P2P PoET SGX enclave uses the following data structures:: WaitTimer { double requestTime double duration byte[32] WaitCertId:sub:`n` double localMean } WaitCertificate { WaitTimer waitTimer byte[32] nonce byte[] blockDigest } It uses the following global variables:: WaitTimer activeWT # The unique active WaitTimer object byte[64] PPK byte[64] PSK MCID # SGX Monotonic Counter Identifier It exports the following functions: ``generateSignUpData(OPKhash)`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Returns** .. code:: console byte[64] PPK byte[432] report # SGX Report Data Structure byte[256] PSEmanifest byte[672] sealedSignUpData # (PPK, PSK, MCID) tuple encrypted with SealKey ****Parameters**** .. code:: console byte[32] OPKhash # SHA256 digest of OPK **Description** 1. Generate fresh ECC key pair (PPK, PSK) #. Create monotonic counter and save its identifier as MCID. #. Use the SGX ``sgx_seal_data()`` function to encrypt (PPK, PSK, MCID) with SealKey (using MRENCLAVE policy) :math:`sealedSignupData = \textnormal{AES-GCM}_{SealKey} (PPK | PSK | MCID)` #. Create SGX enclave report, store ``SHA256(OPKhash|PPK)`` in ``report_data`` field. #. Get SGX PSE manifest: PSEManifest. #. Save (PPK, PSK, MCID) as global variables within the enclave. #. Set active WaitTimer instance activeWT to NULL. #. Return (PPK, report, PSEmanifest, sealedSignUpData). .. note:: **Implementation Note:** Normally, there is a maximum number of monotonic counters that can be created. One way to deal with this limitation is to destroy a previously created monotonic counter if this is not the first time the generateSignupData function was called. ``unsealSignUpData(sealedSignUpData)`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Returns** .. code:: console byte[64] PPK **Parameters** .. code:: console byte[672] sealedSignUpData # (PPK, PSK, MCID) tuple encrypted with SealKey **Description** 1. Use the ``sgx_unseal_data()`` function to decrypt sealedSignUpData into (PPK, PSK, MCID) with SealKey (using MRENCLAVE policy). #. Save (PPK, PSK, MCID) as global variables within the enclave. #. Set global active WaitTimer instance activeWT to NULL. #. Return PPK ``createWaitTimer(localMean, WaitCertId_n)`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Returns** .. code:: console WaitTimer waitTimer byte[64] signature # ECDSA PSK signature of waitTimer **Parameters** .. code:: console double localMean # Estimated wait time local mean byte[32] WaitCertId_n # SHA256 digest of WaitCertificate owner's ECDSA # signature **Description** 1. Increment monotonic counter MCID and store value in global variable counterValue. #. Compute :math:`tag = \textnormal{AES-CMAC}_{PoetSealKey} (WaitCertId_{n})`. #. Convert lowest 64-bits of tag into double precision number in :math:`[0, 1]`: tagd. #. Compute :math:`duration = minimumDuration - localMean * log(tagd)`. #. Set requestTime equal to SGX Trusted Time value. #. Create WaitTimer object :math:`waitTimer = WaitTimer(requestTime, duration, WaitCertId_{n}, localMean)`. #. Compute ECDSA signature of waitTimer using PSK: :math:`signature = ECDSA_{PSK} (waitTimer)`. #. Set global active WaitTimer instance activeWT equal to waitTimer. #. Return (waitTimer, signature). ``createWaitCertificate(blockDigest)`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Returns** .. code:: console WaitCertificate waitCertificate byte[64] signature # ECDSA PSK signature of waitCertificate **Parameters** .. code:: console byte[] blockDigest # ECDSA signature with originator private key of SHA256 # digest of transaction block that the validator wants # to commit **Description** 1. If activeWT is equal to NULL, exit. #. Read monotonic counter MCID and compare its value to global variable counterValue. If values do not match, exit. #. Read SGX Trusted time into variable currentTime. If currentTime is smaller than :math:`waitTimer.requestTime + waitTimer.duration`, exit (the duration has not elapsed yet). #. If currentTime is larger than :math:`waitTimer.requestTime + waitTimer.duration+T_{WT}`, exit. #. Generate random nonce. #. Create WaitCertificate object :math:`waitCertificate = WaitCertificate(waitTimer, nonce, blockDigest)`. #. Compute ECDSA signature of waitCertificate using PSK: :math:`signature = ECDSA_{PSK} (waitCertificate)`. #. Set activeWT to NULL. #. Return (waitCertificate, signature). Sign-up Phase ------------- A participant joins as a validator by downloading the PoET SGX enclave and a SPID certificate for the block chain. The client side of the validator runs the following sign-up procedure: 1. Start PoET SGX enclave: ENC. #. Generate sign-up data: :math:`(PPK, report, PSEmanifest, sealedSignUpData) = \textnormal{ENC.generateSignUpData(OPKhash)}` The ``report_data`` (512 bits) field in the report body includes the SHA256 digest of (OPKhash | PPK). #. Ask SGX Quoting Enclave (QE) for linkable quote on the report (using the validator network's Basename). #. If Self Attestation is enabled in IAS API: request attestation of linkable quote and PSE manifest to IAS. The AEP sent to IAS must contain: * isvEnclaveQuote: base64 encoded quote * pseManifest: base64 encoded PSEmanifest * nonce: :math:`WaitCertId_{n}` The IAS sends back a signed AVR containing a copy of the input AEP and the EPID Pseudonym. #. If Self Attestation is enabled in IAS API: broadcast self-attested join request, (OPK, PPK, AEP, AVR) to known participants. #. If Self Attestation is NOT enabled in IAS API: broadcast join request, (OPK, PPK, quote, PSEmanifest) to known participants. A validator has to wait for :math:`c` block to be published on the distributed ledger before participating in an election. The server side of the validator runs the following sign-up procedure: 1. Wait for a join request. #. Upon arrival of a join request do the verification: If the join request is self attested (Self Attestation is enabled in IAS API): (OPK, PPK, AEP, AVR) a. Verify AVR legitimacy using IAS Report Key and therefore quote legitimacy. #. Verify the ``report_data`` field within the quote contains the SHA256 digest of (OPKhash | PPK). #. Verify the nonce in the AVR is equal to :math:`WaitCertId_{n}`, namely the digest of the most recently committed block. It may be that the sender has not seen :math:`WaitCertId_{n}` yet and could be sending :math:`WaitCertId_{n'}` where :math:`n' minObserved and observed > expected: p = expected / blockCount σ = sqrt(blockCount * p * (1.0 - p)) z = (observed - expected) / σ if z > zmax: return False return True If the z-test fails (False is returned) then the validator under test won elections at a higher average rate than expected. .. Licensed under Creative Commons Attribution 4.0 International License .. https://creativecommons.org/licenses/by/4.0/