def serialize(self):
        """
        Serializes to JSON that can later be reconstituted to an
        EnclaveSignupInfo object

        Returns:
            A JSON string representing the serialized version of the object.
            Note that the sealed signup data is not encluded in the serialized
            data.
        """

        if self._serialized is None:
            # Note - we are not serializing the sealed signup data.  Sealed
            # signup data is meant to be used locally on the system and not
            # serialized and sent to anyone else.
            signup_info_dict = {
                'pbft_public_key': self.pbft_public_key,
                'proof_data': self.proof_data,
                'anti_sybil_id': self.anti_sybil_id
            }

            self._serialized = dict2json(signup_info_dict)

        return self._serialized
    def create_wait_certificate(cls, sealed_signup_data, wait_timer,
                                block_hash):
        with cls._lock:
            # Extract keys from the 'sealed' signup data
            if sealed_signup_data is None:
                raise ValueError('Sealed Signup Data is None')
            signup_data = json2dict(
                base64.b64decode(sealed_signup_data.encode()).decode())
            pbft_private_key = signup_data['pbft_private_key']
            pbft_public_key = signup_data['pbft_public_key']

            if pbft_private_key is None or pbft_public_key is None:
                raise \
                    ValueError(
                        'Invalid signup data. No bgt key(s).')

            try:
                pbft_public_key = Secp256k1PublicKey.from_hex(pbft_public_key)
                pbft_private_key = Secp256k1PrivateKey.from_hex(
                    pbft_private_key)
            except ParseError:
                raise \
                    ValueError(
                        'Invalid signup data. Badly formatted pbft key(s).')

            # Several criteria need to be met before we can create a wait
            # certificate:
            # 1. This signup data was used to sign this timer.
            #    i.e. the key sealed / unsealed by the TEE signed this
            #    wait timer.
            # 2. This timer has expired
            # 3. This timer has not timed out
            #
            # In a TEE implementation we would check HW counter agreement.
            # We can't usefully simulate a HW counter though.
            # i.e. wait_timer.counter_value == signup_data.counter.value

            #
            # Note - we make a concession for the genesis block (i.e., a wait
            # timer for which the previous certificate ID is the Null
            # identifier) in that we don't require the timer to have expired
            # and we don't worry about the timer having timed out.

            if wait_timer is None or \
                    not cls._context.verify(
                        wait_timer.signature,
                        wait_timer.serialize().encode(),
                        pbft_public_key):
                raise \
                    ValueError(
                        'Validator is not using the current wait timer')

            is_not_genesis_block = (wait_timer.previous_certificate_id !=
                                    NULL_BLOCK_IDENTIFIER)

            now = time.time()
            expire_time = \
                wait_timer.request_time + \
                wait_timer.duration

            if is_not_genesis_block and now < expire_time:
                raise \
                    ValueError(
                        'Cannot create wait certificate because timer has '
                        'not expired')

            time_out_time = \
                wait_timer.request_time + \
                wait_timer.duration + \
                TIMER_TIMEOUT_PERIOD

            if is_not_genesis_block and time_out_time < now:
                raise \
                    ValueError(
                        'Cannot create wait certificate because timer '
                        'has timed out')

            # Create a random nonce for the certificate.  For our "random"
            # nonce we will take the timer signature, concat that with the
            # current time, JSON-ize it and create a SHA-256 hash over it.
            # Probably not considered random by security professional
            # standards, but it is good enough for the simulator.
            random_string = \
                dict2json({
                    'wait_timer_signature': wait_timer.signature,
                    'now': datetime.datetime.utcnow().isoformat()
                })
            nonce = hashlib.sha256(random_string.encode()).hexdigest()

            # First create a new enclave wait certificate using the data
            # provided and then sign the certificate with the PBFT private key
            wait_certificate = \
                EnclaveWaitCertificate.wait_certificate_with_wait_timer(
                    wait_timer=wait_timer,
                    nonce=nonce,
                    block_hash=block_hash)
            wait_certificate.signature = \
                cls._context.sign(
                    wait_certificate.serialize().encode(),
                    pbft_private_key)

            # In a TEE implementation we would increment the HW counter here
            # to prevent replay.
            # We can't usefully simulate a HW counter though.

            return wait_certificate
    def create_signup_info(cls, originator_public_key_hash, nonce):
        with cls._lock:
            # First we need to create a public/private key pair for the PBFT
            # enclave to use.
            # Counter ID is a placeholder for a hardware counter in a TEE.
            pbft_private_key = Secp256k1PrivateKey.new_random()
            pbft_public_key = cls._context.get_public_key(pbft_private_key)
            counter_id = None

            # Simulate sealing (encrypting) the signup data.
            signup_data = {
                'pbft_private_key': pbft_private_key.as_hex(),
                'pbft_public_key': pbft_public_key.as_hex(),
                'counter_id': counter_id
            }
            sealed_signup_data = base64.b64encode(
                dict2json(signup_data).encode()).decode('utf-8')
            """
            sgx_quote = b'fake quote'
            # Create a fake PSE manifest.  A base64 encoding of the
            # originator public key hash should suffice.
            pse_manifest = base64.b64encode(originator_public_key_hash.encode())
            """
            timestamp = datetime.datetime.now().isoformat()

            # Fake our "proof" data.
            verification_report = {
                'epidPseudonym':
                cls._anti_sybil_id,
                'id':
                base64.b64encode(
                    hashlib.sha256(
                        timestamp.encode()).hexdigest().encode()).decode(),
                'isvEnclaveQuoteStatus':
                'OK',
                #'isvEnclaveQuoteBody': base64.b64encode(sgx_quote).decode(), # base64.b64encode(sgx_quote.serialize_to_bytes()).decode(),
                'pseManifestStatus':
                'OK',
                #'pseManifestHash': hashlib.sha256(base64.b64decode(pse_manifest)).hexdigest(),
                'nonce':
                nonce,
                'timestamp':
                timestamp
            }

            # Serialize the verification report, sign it, and then put
            # in the proof data
            verification_report_json = dict2json(verification_report)
            signature = cls._report_private_key.sign(
                verification_report_json.encode(), padding.PKCS1v15(),
                hashes.SHA256())

            proof_data_dict = {
                'evidence_payload': {
                    'pse_manifest': '',  #pse_manifest.decode()
                },
                'verification_report': verification_report_json,
                'signature': base64.b64encode(signature).decode()
            }
            proof_data = dict2json(proof_data_dict)

            return EnclaveSignupInfo(
                pbft_public_key=signup_data['pbft_public_key'],
                proof_data=proof_data,
                anti_sybil_id=cls._anti_sybil_id,
                sealed_signup_data=sealed_signup_data)
    def _register_signup_information(self,
                                     block_header,
                                     pbft_enclave_module=None):
        # Create signup information for this validator, putting the block ID
        # of the block previous to the block referenced by block_header in the
        # nonce.  Block ID is better than wait certificate ID for testing
        # freshness as we need to account for non-BGT blocks.
        LOGGER.debug('_register_signup_information: TRY to REGISTER')
        public_key_hash = hashlib.sha256(
            block_header.signer_public_key.encode()).hexdigest()
        nonce = SignupInfo.block_id_to_nonce(block_header.previous_block_id)
        pbft_public_key = self._validator_id
        anti_sybil_id = hashlib.sha256(pbft_public_key.encode()).hexdigest()
        signup_data = {
            'pbft_public_key': pbft_public_key,
        }
        sealed_signup_data = base64.b64encode(
            dict2json(signup_data).encode()).decode('utf-8')
        """
        signup_info = SignupInfo.create_signup_info(
                pbft_enclave_module=pbft_enclave_module,
                originator_public_key_hash=public_key_hash,
                nonce=nonce)
        """
        # Create the validator registry payload
        payload = vr_pb.BgxValidatorRegistryPayload(
            verb='register',
            name='validator-{}'.format(block_header.signer_public_key[:8]),
            id=block_header.signer_public_key,
            node=self._node,
            signup_info=vr_pb.BgxSignUpInfo(
                pbft_public_key=pbft_public_key,  # signup_info.pbft_public_key,
                anti_sybil_id=anti_sybil_id,  # signup_info.anti_sybil_id,
                nonce=nonce),
        )
        serialized = payload.SerializeToString()

        # Create the address that will be used to look up this validator
        # registry transaction.  Seems like a potential for refactoring..
        validator_entry_address = PbftBlockPublisher._validator_registry_namespace + hashlib.sha256(
            block_header.signer_public_key.encode()).hexdigest()

        # Create a transaction header and transaction for the validator
        # registry update amd then hand it off to the batch publisher to
        # send out.
        output_addresses = [
            validator_entry_address, PbftBlockPublisher._validator_map_address
        ]
        input_addresses = output_addresses + \
            [SettingsView.setting_address('sawtooth.bgt.report_public_key_pem'),
             SettingsView.setting_address('sawtooth.bgt.valid_enclave_measurements'),
             SettingsView.setting_address('sawtooth.bgt.valid_enclave_basenames')
            ]

        header = txn_pb.TransactionHeader(
            signer_public_key=block_header.signer_public_key,
            family_name='bgx_validator_registry',
            family_version='1.0',
            inputs=input_addresses,
            outputs=output_addresses,
            dependencies=[],
            payload_sha512=hashlib.sha512(serialized).hexdigest(),
            batcher_public_key=block_header.signer_public_key,
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._batch_publisher.identity_signer.sign(header)

        transaction = txn_pb.Transaction(header=header,
                                         payload=serialized,
                                         header_signature=signature)

        LOGGER.info('Register Validator Name=%s, ID=%s...%s,Nonce=%s',
                    payload.name, payload.id[:8], payload.id[-8:], nonce)

        self._batch_publisher.send([transaction])

        # Store the key state so that we can look it up later if need be and
        # set the new key as our active key
        self._pbft_key_state_store[pbft_public_key] = PbftKeyState(
            sealed_signup_data=sealed_signup_data,
            has_been_refreshed=False,
            signup_nonce=nonce)
        self._pbft_key_state_store.active_key = pbft_public_key
        LOGGER.debug('_register_signup_information: REGISTER DONE')