def _create_blocks(self, block_count, batch_count, valid_block=True, valid_batch=True): block_list = [] for i in range(block_count): batch_list = self._create_batches( batch_count, 2, valid_batch=valid_batch) batch_ids = [batch.header_signature for batch in batch_list] block_header = BlockHeader(signer_pubkey=self.public_key, batch_ids=batch_ids) header_bytes = block_header.SerializeToString() if valid_block: signature = signing.sign( header_bytes, self.private_key) else: signature = "bad_signature" block = Block(header=header_bytes, batches=batch_list, header_signature=signature) block_list.append(block) return block_list
def _send_xo_txn(self, name, action, space=""): # Serialization is just a delimited utf-8 encoded string payload = ",".join([name, action, str(space)]).encode() # Construct the address address = self._get_address(name) header = TransactionHeader( signer_pubkey=self._public_key, family_name="xo", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_encoding="csv-utf8", payload_sha512=_sha512(payload), batcher_pubkey=self._public_key).SerializeToString() signature = signing.sign(header, self._private_key) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) result = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') return result
def _create_batches(self, batch_count, txn_count, valid_batch=True, valid_txn=True, valid_batcher=True): batch_list = [] for i in range(batch_count): txn_list = self._create_transactions(txn_count, valid_txn, valid_batcher) txn_sig_list = [txn.header_signature for txn in txn_list] batch_header = BatchHeader(signer_pubkey=self.public_key) batch_header.transaction_ids.extend(txn_sig_list) header_bytes = batch_header.SerializeToString() if valid_batch: signature = signing.sign( header_bytes, self.private_key) else: signature = "bad_signature" batch = Batch(header=header_bytes, transactions=txn_list, header_signature=signature) batch_list.append(batch) return batch_list
def test_deserialized_wait_timer(self): wait_timer = \ EnclaveWaitTimer( duration=3.14159, previous_certificate_id='Bond. James Bond.', local_mean=2.71828) serialized = wait_timer.serialize() signing_key = self._create_random_key() wait_timer.signature = \ signing.sign(serialized, signing_key) copy_wait_timer = \ EnclaveWaitTimer.wait_timer_from_serialized( serialized, wait_timer.signature) self.assertAlmostEquals( wait_timer.request_time, copy_wait_timer.request_time) self.assertAlmostEquals( wait_timer.duration, copy_wait_timer.duration) self.assertEqual( wait_timer.previous_certificate_id, copy_wait_timer.previous_certificate_id) self.assertAlmostEquals( wait_timer.local_mean, copy_wait_timer.local_mean) self.assertEqual( wait_timer.signature, copy_wait_timer.signature) self.assertEqual(serialized, copy_wait_timer.serialize())
def create_wait_timer(cls, validator_address, previous_certificate_id, local_mean, minimum_wait_time): with cls._lock: # If we don't have a PoET private key, then the enclave has not # been properly initialized (either by calling create_signup_info # or unseal_signup_data) if cls._poet_private_key is None: raise \ ValueError( 'Enclave must be initialized before attempting to ' 'create a wait timer') # Create some value from the cert ID. We are just going to use # the seal key to sign the cert ID. We will then use the # low-order 64 bits to change that to a number [0, 1] tag = \ base64.b64decode( signing.sign( previous_certificate_id, cls._seal_private_key)) tagd = float(struct.unpack('Q', tag[-8:])[0]) / (2**64 - 1) # Now compute the duration with a minimum wait time guaranteed duration = minimum_wait_time - local_mean * math.log(tagd) # Create and sign the wait timer wait_timer = \ EnclaveWaitTimer( validator_address=validator_address, duration=duration, previous_certificate_id=previous_certificate_id, local_mean=local_mean) wait_timer.signature = \ signing.sign( wait_timer.serialize(), cls._poet_private_key) # Keep track of the active wait timer cls._active_wait_timer = wait_timer return wait_timer
def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_pubkey=self._public_key, transaction_ids=transaction_signatures).SerializeToString() signature = signing.sign(header, self._private_key) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
def sign_object(self, signingkey): """Generates a string signature for the object using the signing key. Args: signingkey (str): hex encoded private key """ self._originator_id = None serialized = self.serialize(signable=True) self.Signature = signing.sign(serialized, signingkey) self._recover_verifying_address() self._identifier = hashlib.sha256(self.Signature).hexdigest()
def _sign_message_with_transaction(transaction, message_type, key): """ Signs a transaction message or transaction :param transaction (dict): :param key (str): A signing key returns message, txnid (tuple): The first 16 characters of a sha256 hexdigest. """ transaction['Nonce'] = time.time() pub = signing.encode_pubkey(signing.generate_pubkey(key), "hex") transaction["public_key"] = pub sig = signing.sign(_dict2cbor(transaction), key) transaction['Signature'] = sig txnid = hashlib.sha256(transaction['Signature']).hexdigest()[:16] message = { 'Transaction': transaction, '__TYPE__': message_type, '__NONCE__': time.time(), } cbor_serialized_message = _dict2cbor(message) signature = signing.sign(cbor_serialized_message, key) message['__SIGNATURE__'] = signature return message, txnid
def _sign_block(self, block): """ The block should be complete and the final signature from the publishing validator(this validator) needs to be added. """ # Temp signature creation to use as identifier temp_key = signing.generate_privkey() public_key = signing.encode_pubkey(signing.generate_pubkey(temp_key), "hex") block.block_header.signer_pubkey = public_key block_header = block.block_header header_bytes = block_header.SerializeToString() signature = signing.sign(header_bytes, temp_key) block.set_signature(signature) return block
def _create_transactions(self, count, valid=True, valid_batcher=True): txn_list = [] for i in range(count): payload = {'Verb': 'set', 'Name': 'name' + str(random.randint(0, 100)), 'Value': random.randint(0, 100)} intkey_prefix = \ hashlib.sha512('intkey'.encode('utf-8')).hexdigest()[0:6] addr = intkey_prefix + \ hashlib.sha512(payload["Name"].encode('utf-8')).hexdigest() payload_encode = hashlib.sha512(cbor.dumps(payload)).hexdigest() header = TransactionHeader( signer_pubkey=self.public_key, family_name='intkey', family_version='1.0', inputs=[addr], outputs=[addr], dependencies=[], payload_encoding="application/cbor", payload_sha512=payload_encode) if valid_batcher: header.batcher_pubkey = self.public_key else: header.batcher_pubkey = "bad_batcher" header_bytes = header.SerializeToString() if valid: signature = signing.sign( header_bytes, self.private_key) else: signature = "bad_signature" transaction = Transaction( header=header_bytes, payload=cbor.dumps(payload), header_signature=signature) txn_list.append(transaction) return txn_list
def test_deserialized_wait_certificate(self): wait_timer = \ EnclaveWaitTimer( validator_address='1600 Pennsylvania Avenue NW', duration=3.14159, previous_certificate_id='Smart, Maxwell Smart', local_mean=2.71828) wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=wait_timer, nonce='Eeny, meeny, miny, moe.', block_digest='Indigestion. Pepto Bismol.') serialized = wait_certificate.serialize() signing_key = self._create_random_key() wait_certificate.signature = \ signing.sign(serialized, signing_key) copy_wait_certificate = \ EnclaveWaitCertificate.wait_certificate_from_serialized( serialized, wait_certificate.signature) self.assertAlmostEquals(wait_certificate.request_time, copy_wait_certificate.request_time) self.assertAlmostEquals(wait_certificate.duration, copy_wait_certificate.duration) self.assertEqual(wait_certificate.previous_certificate_id, copy_wait_certificate.previous_certificate_id) self.assertAlmostEquals(wait_certificate.local_mean, copy_wait_certificate.local_mean) self.assertEqual(wait_certificate.validator_address, copy_wait_certificate.validator_address) self.assertEqual(wait_certificate.nonce, copy_wait_certificate.nonce) self.assertEqual(wait_certificate.block_digest, copy_wait_certificate.block_digest) self.assertEqual(wait_certificate.signature, copy_wait_certificate.signature) self.assertEqual(serialized, copy_wait_certificate.serialize())
def test_is_valid_pub_key(self): pubkey = signing.generate_pubkey("5KQ4iQQGgbQX9MmfiPUwwHBL1R" "GPa86NwFbqrWoodjuzruqFVDd") pub = signing.encode_pubkey(pubkey, "hex") minfo = { 'Nonce': 100, 'PublicKey': pub, 'TransactionType': '/Transaction', 'Dependencies': [] } sig = signing.sign( signed_object.dict2cbor(minfo), "5KQ4iQQGgbQX9MmfiPUwwHBL1RGPa86NwFbqrWoodjuzruqFVDd") # Create valid transaction minfo["Signature"] = sig temp = Transaction(minfo) self.assertTrue(temp.is_valid("unused")) # Change transaction after it was signed minfo["Nonce"] = time.time() temp = Transaction(minfo) self.assertFalse(temp.is_valid("unused"))
def create_signup_info(cls, originator_public_key_hash, most_recent_wait_certificate_id): with cls._lock: # First we need to create a public/private key pair for the PoET # enclave to use. cls._poet_private_key = signing.generate_privkey() cls._poet_public_key = \ signing.generate_pubkey(cls._poet_private_key) cls._active_wait_timer = None # We are going to fake out the sealing the signup data. signup_data = { 'poet_public_key': signing.encode_pubkey(cls._poet_public_key, 'hex'), 'poet_private_key': signing.encode_privkey(cls._poet_private_key, 'hex') } sealed_signup_data = \ base64.b64encode(dict2json(signup_data)) # Create a fake report report_data = '{0}{1}'.format( originator_public_key_hash.upper(), signing.encode_pubkey(cls._poet_public_key, 'hex').upper()) quote = { 'report_body': hashlib.sha256(dict2json(report_data)).hexdigest() } # Fake our "proof" data. verification_report = { 'id': base64.b64encode( hashlib.sha256( datetime.datetime.now().isoformat()).hexdigest()), 'isvEnclaveQuoteStatus': 'OK', 'isvEnclaveQuoteBody': base64.b64encode(dict2json(quote)), 'pseManifestStatus': 'OK', 'pseManifestHash': base64.b64encode( hashlib.sha256(b'Do you believe in ' 'manifest destiny?').hexdigest()), 'nonce': most_recent_wait_certificate_id } proof_data_dict = { 'verification_report': dict2json(verification_report), 'signature': signing.sign(dict2json(verification_report), cls._report_private_key) } proof_data = dict2json(proof_data_dict) return \ EnclaveSignupInfo( poet_public_key=signup_data['poet_public_key'], proof_data=proof_data, anti_sybil_id=originator_public_key_hash, sealed_signup_data=sealed_signup_data)
def create_wait_certificate(cls, block_digest): with cls._lock: # If we don't have a PoET private key, then the enclave has not # been properly initialized (either by calling create_signup_info # or unseal_signup_data) if cls._poet_private_key is None: raise \ WaitCertificateError( 'Enclave must be initialized before attempting to ' 'create a wait certificate') # Several criteria need to be met before we can create a wait # certificate: # 1. We have an active timer # 2. The active timer has expired # 3. The active timer has not timed out # # 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 cls._active_wait_timer is None: raise \ WaitCertificateError( 'Enclave active wait timer has not been initialized') is_not_genesis_block = \ (cls._active_wait_timer.previous_certificate_id != NullIdentifier) now = time.time() expire_time = \ cls._active_wait_timer.request_time + \ cls._active_wait_timer.duration if is_not_genesis_block and now < expire_time: raise \ WaitCertificateError( 'Cannot create wait certificate because timer has ' 'not expired') time_out_time = \ cls._active_wait_timer.request_time + \ cls._active_wait_timer.duration + \ TIMER_TIMEOUT_PERIOD if is_not_genesis_block and time_out_time < now: raise \ WaitCertificateError( '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': cls._active_wait_timer.signature, 'now': datetime.datetime.utcnow().isoformat() }) nonce = hashlib.sha256(random_string).hexdigest() # First create a new enclave wait certificate using the data # provided and then sign the certificate with the PoET private key wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=cls._active_wait_timer, nonce=nonce, block_digest=block_digest) wait_certificate.signature = \ signing.sign( wait_certificate.serialize(), cls._poet_private_key) # Now that we have created the certificate, we no longer have an # active timer cls._active_wait_timer = None return wait_certificate