Ejemplo n.º 1
0
class ChainPointV2(object):
    def __init__(self, hash_type="sha256"):
        self.hash_type = hash_type.lower()
        self.mk = MerkleTools(hash_type)

    '''Wraps merkletools method'''

    def reset_tree(self):
        self.mk.reset_tree()

    '''Wraps merkletools method'''

    def add_leaf(self, values, do_hash=False):
        self.mk.add_leaf(values, do_hash)

    '''Wraps merkletools method'''

    def get_leaf(self, index):
        return self.mk.get_leaf(index)

    '''Wraps merkletools method'''

    def get_leaf_count(self):
        return self.mk.get_leaf_count()

    '''Wraps merkletools method'''

    def get_tree_ready_state(self):
        return self.mk.get_tree_ready_state()

    '''Wraps merkletools method'''

    def make_tree(self):
        self.mk.make_tree()

    '''Wraps merkletools method'''

    def get_merkle_root(self):
        return self.mk.get_merkle_root()

    '''Wraps merkletools method'''

    def get_proof(self, index):
        return self.mk.get_proof(index)

    '''Wraps merkletools method'''

    def validate_proof(self, proof, target_hash, merkle_root):
        return self.mk.validate_proof(proof, target_hash, merkle_root)

    def get_chainpoint_hash_type(self):
        return CHAINPOINT_HASH_TYPES[self.hash_type]

    '''
    Returns the chainpoint v2 blockchain receipt for specific leaf
    Currently only works for BTC anchors
    '''

    def get_receipt(self, index, btc_source_id):
        if self.get_tree_ready_state():
            return {
                "@context": CHAINPOINT_CONTEXT,
                "type": self.get_chainpoint_hash_type(),
                "targetHash": self.get_leaf(index),
                "merkleRoot": self.get_merkle_root(),
                "proof": self.get_proof(index),
                "anchors": [{
                    "type": "BTCOpReturn",
                    "sourceId": btc_source_id
                }]
            }
        else:
            return None

    '''
    Validates a chainpoint receipt. Currently only for BTC anchors
        receipt is the chainpoint_proof metadata from the pdf file.
        certificate_hash is the hash of the certificate after we removed the
            chainpoint_proof metadata
        issuer_identifier is a fixed 8 bytes issuer code that displays on the
            blockchain
        testnet specifies if testnet or mainnet was used
    '''

    # TODO consider using exceptions instead of (bool, text) tuples; this is
    # really only needed for valid but soon to expire
    def validate_receipt(self,
                         receipt,
                         certificate_hash,
                         issuer_identifier='',
                         testnet=False):
        # check context and hash type
        if (receipt['@context'].lower() != CHAINPOINT_CONTEXT):
            return False, "wrong chainpoint context"
        if (receipt['type'] not in CHAINPOINT_HASH_TYPES.values()):
            return False, "type not in CHAINPOINT_HASH_TYPES"
        target_hash = receipt['targetHash']
        merkle_root = receipt['merkleRoot']
        proof = receipt['proof']

        # validate actual hash
        if target_hash.lower() != certificate_hash.lower():
            return False, "certificate hash is different than the one in receipt"

        # validate merkle proof
        if (not self.validate_proof(proof, target_hash, merkle_root)):
            return False, "certificate's hash is not in merkle root"

        txid = self.get_txid_from_receipt(receipt)

        # validate anchor
        op_return_hex = network_utils.get_op_return_hex_from_blockchain(
            txid, testnet)

        # ignore issuer_identifier for now (it is string in CRED but used to be
        # hex so we need a smart way to get it) -- TODO: obsolete it !!!
        #issuer_id_hex = utils.text_to_hex(issuer_identifier)

        # if op_return starts with CRED it is using the meta-protocol
        op_dict = cred_protocol.parse_op_return_hex(op_return_hex)
        if op_dict:
            version_hex = op_dict['version']
            command_hex = op_dict['cmd']
            # could check if it is equal to issuer_id_hex
            issuer_hex = op_dict['data']['issuer_identifier']
            # get merkle root
            hash_hex = op_dict['data']['merkle_root']
            # if issue with expiry get expiry date
            if command_hex == cred_protocol.hex_op('op_issue_abs_expiry'):
                expiry_hex = op_return_hex[96:116]
            else:
                expiry_hex = None
            #print(version_hex)
            #print(command_hex)
            #print(issuer_hex)
            #print(hash_hex)
            #print(merkle_root.lower())
        # otherwise op_return should be fixed to 7 bytes or 14 hex chars (old prefix method)
        else:
            ignore_hex_chars = 14
            hash_hex = op_return_hex[ignore_hex_chars:]

        if (not merkle_root.lower() == hash_hex.lower()):
            return False, "certificate's merkle root is different than the one in the blockchain"

        # only for CRED protocol certificates check expiration date if
        # issued with expiry date
        if op_dict and expiry_hex:
            expiry = utils.hex_to_int(expiry_hex)
            if expiry > int(time.time()):
                return True, "valid until: " + str(expiry)
            else:
                return False, "certificate expired at: " + str(expiry)

        return True, None


#    def get_op_return_hex_from_blockchain(self, txid, testnet):
#        # uses blockcypher API for now -- TODO: expand to consult multiple services
#        if testnet:
#            blockcypher_url = "https://api.blockcypher.com/v1/btc/test3/txs/" + txid
#        else:
#            blockcypher_url = "https://api.blockcypher.com/v1/btc/main/txs/" + txid
#
#        response = requests.get(blockcypher_url).json()
#        outputs = response['outputs']
#        hash_hex = ""
#        for o in outputs:
#            script = o['script']
#            if script.startswith('6a'):
#                # when > 75 op_pushdata1 (4c) is used before length
#                if script.startswith('6a4c'):
#                    # 2 for 1 byte op_return + 2 for 1 byte op_pushdata1 + 2 for 1 byte data length
#                    ignore_hex_chars = 6
#                else:
#                    # 2 for 1 byte op_return + 2 for 1 byte data length
#                    ignore_hex_chars = 4
#
#                hash_hex = script[ignore_hex_chars:]
#                break
#        return hash_hex

    def get_txid_from_receipt(self, receipt):
        # get anchor
        # TODO currently gets only the first valid (BTC) anchor
        anchors = receipt['anchors']
        txid = ''
        for a in anchors:
            if a['type'] in CHAINPOINT_ANCHOR_TYPES.values():
                txid = a['sourceId']
                break
        return txid
Ejemplo n.º 2
0
class ChainPointV2(object):
    def __init__(self, hash_type="sha256"):
        self.hash_type = hash_type.lower()
        self.mk = MerkleTools(hash_type)

    '''Wraps merkletools method'''
    def reset_tree(self):
        self.mk.reset_tree()

    '''Wraps merkletools method'''
    def add_leaf(self, values, do_hash=False):
        self.mk.add_leaf(values, do_hash)

    '''Wraps merkletools method'''
    def get_leaf(self, index):
        return self.mk.get_leaf(index)

    '''Wraps merkletools method'''
    def get_leaf_count(self):
        return self.mk.get_leaf_count()

    '''Wraps merkletools method'''
    def get_tree_ready_state(self):
        return self.mk.get_tree_ready_state()

    '''Wraps merkletools method'''
    def make_tree(self):
        self.mk.make_tree()

    '''Wraps merkletools method'''
    def get_merkle_root(self):
        return self.mk.get_merkle_root()

    '''Wraps merkletools method'''
    def get_proof(self, index):
        return self.mk.get_proof(index)

    '''Wraps merkletools method'''
    def validate_proof(self, proof, target_hash, merkle_root):
        return self.mk.validate_proof(proof, target_hash, merkle_root)

    def get_chainpoint_hash_type(self):
        return CHAINPOINT_HASH_TYPES[self.hash_type]

    '''
    Returns the chainpoint v2 blockchain receipt for specific leaf
    Currently only works for bitcoin and litecoin anchors
    '''
    def get_receipt(self, index, source_id, chain, testnet):

        chain_type = utils.get_chain_type(chain, testnet)

        if(chain_type is not None and self.get_tree_ready_state()):
            return {
                "@context": CHAINPOINT_CONTEXT,
                "type": self.get_chainpoint_hash_type(),
                "targetHash": self.get_leaf(index),
                "merkleRoot": self.get_merkle_root(),
                "proof": self.get_proof(index),
                "anchors": [
                    {
                        "type": CHAINPOINT_ANCHOR_TYPES[chain_type],
                        "sourceId": source_id
                    }
                ]
            }
        else:
            return None


    '''
    Validates a chainpoint receipt. Currently for BTC and LTC anchors
        receipt is the chainpoint_proof metadata from the pdf file.
        certificate_hash is the hash of the certificate after we removed the
            chainpoint_proof metadata
        issuer_identifier is a fixed 8 bytes issuer code that displays on the
            blockchain
    '''
    # TODO consider using exceptions instead of (bool, text) tuples; this is
    # really only needed for valid but soon to expire
    def validate_receipt(self, receipt, op_return_hex, certificate_hash, issuer_identifier=''):
        # check context and hash type
        if(receipt['@context'].lower() != CHAINPOINT_CONTEXT):
            return False, "wrong chainpoint context"
        if(receipt['type'] not in CHAINPOINT_HASH_TYPES.values()):
            return False, "chainpoint type not in CHAINPOINT_HASH_TYPES"
        # currently only one anchor at a time is allowed; thus 0
        if(receipt['anchors'][0]['type'] not in CHAINPOINT_ANCHOR_TYPES.values()):
            return False, "anchor type not in CHAINPOINT_ANCHOR_TYPES"
        target_hash = receipt['targetHash']
        merkle_root = receipt['merkleRoot']
        proof = receipt['proof']

        # validate actual hash
        if target_hash.lower() != certificate_hash.lower():
            return False, "certificate hash is different than the one in receipt"

        # validate merkle proof
        if(not self.validate_proof(proof, target_hash, merkle_root)):
           return False, "certificate's hash is not in merkle root"

        # ignore issuer_identifier for now (it is string in CRED but used to be
        # hex so we need a smart way to get it) -- TODO: obsolete it !!!
        #issuer_id_hex = utils.text_to_hex(issuer_identifier)

        # if op_return starts with CRED it is using the meta-protocol
        op_dict = cred_protocol.parse_op_return_hex(op_return_hex)
        if op_dict:
            version_hex = op_dict['version']
            command_hex = op_dict['cmd']
            # could check if it is equal to issuer_id_hex
            issuer_hex = op_dict['data']['issuer_identifier']
            # get merkle root
            hash_hex = op_dict['data']['merkle_root']
            # if issue with expiry get expiry date
            if command_hex == cred_protocol.hex_op('op_issue_abs_expiry'):
                expiry_hex = op_return_hex[96:116]
            else:
                expiry_hex = None
            #print(version_hex)
            #print(command_hex)
            #print(issuer_hex)
            #print(hash_hex)
            #print(merkle_root.lower())
        # otherwise op_return should be fixed to 7 bytes or 14 hex chars (old prefix method)
        else:
            ignore_hex_chars = 14
            hash_hex = op_return_hex[ignore_hex_chars:]

        if(not merkle_root.lower() == hash_hex.lower()):
            return False, "certificate's merkle root is different than the one in the blockchain"

        # only for CRED protocol certificates check expiration date if
        # issued with expiry date
        if op_dict and expiry_hex:
            expiry = utils.hex_to_int(expiry_hex)
            if expiry > int(time.time()):
                return True, "valid until: " + str(expiry)
            else:
                return False, "certificate expired at: " + str(expiry)


        return True, None



    # TODO: DELETE - NOT USED ANYWHERE !!
    def get_chain_testnet_txid_from_receipt(self, receipt):
        # get anchor
        # TODO currently gets only the first valid anchor
        anchors = receipt['anchors']
        chain = ''
        testnet = False
        txid = ''
        for a in anchors:
            if a['type'] in CHAINPOINT_ANCHOR_TYPES.values():
                if(a['type'] == 'BTCOpReturn'):
                    chain = 'bitcoin'
                    testnet = False
                elif(a['type'] == 'LTCOpReturn'):
                    chain = 'litecoin'
                    testnet = False
                elif(a['type'] == 'BTCTestnetOpReturn'):
                    chain = 'bitcoin'
                    testnet = True
                elif(a['type'] == 'LTCTestnetOpReturn'):
                    chain = 'litecoin'
                    testnet = True

            txid = a['sourceId']
            break

        return chain, testnet, txid
Ejemplo n.º 3
0
def test_add_leaf():
    mt = MerkleTools()
    mt.add_leaf("tierion")
    mt.add_leaf(["bitcoin", "blockchain"])
    assert mt.get_leaf_count() == 3
    assert mt.is_ready is False
def test_add_leaf():
    mt = MerkleTools()
    mt.add_leaf("tierion", do_hash=True)
    mt.add_leaf(["bitcoin", "blockchain"], do_hash=True)
    assert mt.get_leaf_count() == 3
    assert mt.is_ready == False
import merkletools
from merkletools import MerkleTools
from hashlib import sha256
import json

myMerkleT = MerkleTools(hash_type="sha256")      # This will make use of SHA256

myMerkleT.add_leaf(["Security", "Room14", "Professor"], True)              #  My first leaves.
myMerkleT.add_leaf(["Room12", "blockchain", "Python"], True)   # This adds three leaves to the Tree.
myMerkleT.add_leaf(["Name:Justice", "Course:Computer Science"], True) # Another three leaves.


myMerkleT.make_tree()      # Creating the Merkle Tree.

print('')
numberOfLeaves = myMerkleT.get_leaf_count()

print("The number of leaves of this tree is: ", numberOfLeaves)

print("root:", myMerkleT.get_merkle_root())  

print("The value at leaf 2 is: ", myMerkleT.get_leaf(2))

print("The array of hash objects for the leaf at index 2 is: ", myMerkleT.get_proof(2))  
                     
print('')
print('************************ Merkle Proof ****************************')
print(myMerkleT.validate_proof(myMerkleT.get_proof(2), myMerkleT.get_leaf(2), myMerkleT.get_merkle_root())) # True
print('************************ Merkle Proof ****************************')

TestData = ["My Professor is helping me to learn well."]
Ejemplo n.º 6
0
from merkletools import MerkleTools

mt = MerkleTools()

mt.add_leaf("tierion", True)
mt.add_leaf(["bitcoin", "blockchain"], True)

mt.make_tree()

print mt.get_leaf_count()

print "root:", mt.get_merkle_root(
)  # root: '777765f15d171871b00034ee55e48ffdf76afbc44ed0bcff5c82f31351d333c2ed1'

print mt.get_proof(
    1
)  # [{left: '2da7240f6c88536be72abe9f04e454c6478ee29709fc3729ddfb942f804fbf08'},
#  {right: 'ef7797e13d3a75526946a3bcf00daec9fc9c9c4d51ddc7cc5df888f74dd434d1'}]

print mt.validate_proof(mt.get_proof(1), mt.get_leaf(1), mt.get_merkle_root())