def do_test_signature(self, chain, display_chain, type): merkle_tree_generator = MerkleTreeGenerator() merkle_tree_generator.populate(get_test_data_generator()) _ = merkle_tree_generator.get_blockchain_data() gen = merkle_tree_generator.get_proof_generator( '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', chain) p1 = next(gen) _ = next(gen) p3 = next(gen) p1_expected = {'type': ['MerkleProof2017', 'Extension'], 'merkleRoot': '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044', 'targetHash': '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', 'proof': [{'right': 'd4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35'}, {'right': '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'}], 'anchors': [ {'sourceId': '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', 'type': type, 'chain': display_chain}]} p3_expected = {'type': ['MerkleProof2017', 'Extension'], 'merkleRoot': '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044', 'targetHash': '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce', 'proof': [{'left': '4295f72eeb1e3507b8461e240e3b8d18c1e7bd2f1122b11fc9ec40a65894031a'}], 'anchors': [{'sourceId': '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', 'type': type, 'chain': display_chain}]} self.assertEqual(p1, p1_expected) self.assertEqual(p3, p3_expected)
def test_generate(self): merkle_tree_generator = MerkleTreeGenerator() merkle_tree_generator.populate(get_test_data_generator()) byte_array = merkle_tree_generator.get_blockchain_data() self.assertEqual( b2h(byte_array), '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044')
def test_proofs(self): merkle_tree_generator = MerkleTreeGenerator() merkle_tree_generator.populate(get_test_data_generator()) _ = merkle_tree_generator.get_blockchain_data() gen = merkle_tree_generator.get_proof_generator( '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', Chain.mainnet) p1 = next(gen) _ = next(gen) p3 = next(gen) p1_expected = {'type': ['MerkleProof2017', 'Extension'], 'merkleRoot': '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044', 'targetHash': '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', 'proof': [{'right': 'd4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35'}, {'right': '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'}], 'anchors': [ {'sourceId': '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', 'type': 'BTCOpReturn'}]} p3_expected = {'type': ['MerkleProof2017', 'Extension'], 'merkleRoot': '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044', 'targetHash': '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce', 'proof': [{'left': '4295f72eeb1e3507b8461e240e3b8d18c1e7bd2f1122b11fc9ec40a65894031a'}], 'anchors': [{'sourceId': '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', 'type': 'BTCOpReturn'}]} self.assertEqual(p1, p1_expected) self.assertEqual(p3, p3_expected)
class SimplifiedCertificateBatchIssuer: """ Class to issue blockcerts without relying on filesystem usage. Please note that it currently only supports anchoring to Ethereum. """ def __init__(self, config: 'AttrDict', unsigned_certs: dict): # 1- Prepare config and unsigned certs (These come from my latest changes in cert-tools self.config = config self.config.original_chain = self.config.chain self.config.chain = Chain.parse_from_chain(self.config.chain) self.path_to_secret = os.path.join(config.usb_name, config.key_file) self.unsigned_certs = unsigned_certs self.cert_generator = self._create_cert_generator() # 2- Calculate Merkle Tree and Root self.merkle_tree_generator = MerkleTreeGenerator() self.merkle_tree_generator.populate(self.cert_generator) self.merkle_root = self.merkle_tree_generator.get_blockchain_data() def issue(self) -> Tuple[str, Dict]: """Anchor the merkle root in a blockchain transaction and add the tx id and merkle proof to each cert.""" tx_id = self._broadcast_transaction() signed_certs = self._add_proof_to_certs(tx_id) return tx_id, signed_certs def _add_proof_to_certs(self, tx_id) -> Dict: """Add merkle proof to the JSON of the certificates.""" proof_generator = self.merkle_tree_generator.get_proof_generator( tx_id, self.config.chain) signed_certs = copy.deepcopy(self.unsigned_certs) for _, cert in signed_certs.items(): proof = next(proof_generator) cert['signature'] = proof return signed_certs def _broadcast_transaction(self) -> str: """Broadcast the tx used to anchor a merkle root to a given blockchain.""" self.transaction_handler = SimplifiedEthereumTransactionHandler( chain=self.config.original_chain.split('_')[1], path_to_secret=self.path_to_secret, private_key=self.config.get('eth_private_key'), recommended_max_cost=self.config.gas_price * self.config.gas_limit, account_from=self.config.get('eth_public_key') or self.config.issuing_address, ) tx_id = self.transaction_handler.issue_transaction(self.merkle_root) return tx_id def _create_cert_generator(self) -> Generator: """Return a generator of jsonld-normalized unsigned certs.""" for uid, cert in self.unsigned_certs.items(): normalized = normalize_jsonld(cert, detect_unmapped_fields=False) yield normalized.encode('utf-8')
def test_generate(self): merkle_tree_generator = MerkleTreeGenerator() merkle_tree_generator.populate(get_test_data_generator()) byte_array = merkle_tree_generator.get_blockchain_data() self.assertEqual(b2h(byte_array), '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044')
def do_test_signature(self, chain, display_chain, type): self.maxDiff = None app_config = mock.Mock() app_config.issuing_method = "transaction" merkle_tree_generator = MerkleTreeGenerator() merkle_tree_generator.populate(get_test_data_generator()) _ = merkle_tree_generator.get_blockchain_data() gen = merkle_tree_generator.get_proof_generator( '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582', 'http://example.com', chain) p1 = next(gen) _ = next(gen) p3 = next(gen) p1_json_proof = { 'path': [{ 'right': 'd4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35' }, { 'right': '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce' }], 'merkleRoot': '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044', 'targetHash': '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', 'anchors': [ helpers.tx_to_blink( chain, '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582' ) ] } mp2019 = MerkleProof2019() proof_value = mp2019.encode(p1_json_proof) p1_expected = { "type": "MerkleProof2019", "created": p1['created'], "proofValue": proof_value.decode('utf8'), "proofPurpose": "assertionMethod", "verificationMethod": "http://example.com" } p3_json_proof = { 'path': [{ 'left': '4295f72eeb1e3507b8461e240e3b8d18c1e7bd2f1122b11fc9ec40a65894031a' }], 'merkleRoot': '0932f1d2e98219f7d7452801e2b64ebd9e5c005539db12d9b1ddabe7834d9044', 'targetHash': '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce', 'anchors': [ helpers.tx_to_blink( chain, '8087c03e7b7bc9ca7b355de9d9d8165cc5c76307f337f0deb8a204d002c8e582' ) ] } mp2019 = MerkleProof2019() proof_value = mp2019.encode(p3_json_proof) p3_expected = { "type": "MerkleProof2019", "created": p3['created'], "proofValue": proof_value.decode('utf8'), "proofPurpose": "assertionMethod", "verificationMethod": "http://example.com" } self.assertEqual(p1, p1_expected) self.assertEqual(p3, p3_expected)