Notarizing a file and verifying its authenticity

In this tutorial, you will take a file, calculate the hash value of its contents by using a cryptographic hash function, send this value to the notary service for writing it to the Ethereum blockchain (notarize the file), and then pass this value to the service again to check if the service has indeed written it to the blockchain (verify the file authenticity).

Step-by-step procedure

  1. Start the Python shell and configure its session.

    The following variables should be available now:

    >>> base_url  # the base URL of the API
    'https://eu2-cloud.acronis.com/api/notary/v2'
    >>> auth  # the 'Authorization' header value with the access token
    {'Authorization': 'Bearer 8770b34b74f9e4d9424eff50c38182bb4ae7f5596582ae61900b1b6a23e3ec58'}
    
  2. Define a variable named file_path, and then assign the path to your file to this variable:

    >>> file_path = '<path to file>'
    

    Important

    If the path contains backslashes, remember to escape them with an additional backslash.

  3. Open the file for reading in binary mode:

    >>> file = open(file_path, 'rb')
    
  4. Calculate the hash value of the file contents by using the SHA-256 algorithm:

    >>> sha256 = hashlib.sha256()
    >>> chunk = file.read(128 * sha256.block_size)
    >>> while chunk:
    ...     sha256.update(chunk)
    ...     chunk = file.read(128 * sha256.block_size)
    >>> file_hash = sha256.hexdigest()
    >>> file_hash
    '2c7c3d5f244f1a40069a32224215e0cf9b42485c99d80f357d76f006359c7a18'
    
  5. Close the file:

    >>> file.close()
    
  6. Fetch the file name from the file path:

    >>> file_name = os.path.basename(file_path)
    
  7. Define a variable named metadata, and then assign an object with the following JSON parameters to this variable:

    >>> metadata = {
    ...     'GUID': file_name,
    ...     'eTag': file_hash
    ... }
    

    You may specify other information about the file in additional keys. Refer to the API reference for more information.

    Warning

    • Do not specify sensitive information in this object because the entire object contents will be available in the notarization certificate that will be created for the object when you send it to the notary service.

    • Key names are case-sensitive. For example, if you do not write eTag as shown in the snippet above, the notary service will calculate the SHA-256 hash value of the entire object contents and write this value to the blockchain. Thus, an attempt to later verify the file’s authenticity will fail.

  8. Convert the metadata object to a JSON text:

    >>> metadata = json.dumps(metadata, indent=4)
    
  9. Send a POST request with the JSON text to the /meta endpoint:

    >>> response = requests.post(
    ...     f'{base_url}/meta',
    ...     headers={'Content-Type': 'application/json', **auth},
    ...     data=metadata,
    ... )
    
  10. Check the status code of the response:

    >>> response.status_code
    200
    

    The 200 code means the following:

    • The object has been successfully sent to the notary service.

    • The service has received the object.

    • The service has queued the hash value specified in the object’s eTag key for writing it to the blockchain.

      Note

      The writing of queued hash values is triggered every hour and the time when the writing is completed depends on the Ethereum network status.

      Important

      It is not possible to delete a value from the queue and cancel the notarization.

    • The service has created a notarization certificate for the object.

    A different code means that an error has occurred. For more information, refer to “Status and error codes”.

  11. Convert the JSON text that the response body contains to an object, and then fetch the ID of the created notarization certificate:

    >>> certificate_id = response.json()['certificate_id']
    >>> certificate_id
    '7605f73deaee7b071a570b3ac20cc9fe7a3abf337be7c86c55c28af9d3d8435c'
    
  12. Check the notarization status by sending a GET request to the /certificates/{certificate_id} endpoint. We recommend waiting about an hour before checking because the notarization process may take a long time:

    >>> response = requests.get(f'{base_url}/certificates/{certificate_id}', headers=auth)
    
  13. Check the status code of the response:

    >>> response.status_code
    200
    

    Status code 200 means that the request was successful.

    A different status code means that an error has occurred. For the details, refer to “Status and error codes”.

    Also, the response body contains the notarization certificate object formatted as a JSON text. When converted to an object, it will look as follows:

    >>> pprint.pprint(response.json())
    {'contract': '0xd10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF',
     'eventtime': '2019-11-11T13:07:07.004366Z',
     'id': '7605f73deaee7b071a570b3ac20cc9fe7a3abf337be7c86c55c28af9d3d8435c',
     'merkle_proof': '[{"left":"88c20ca21dd6fa9e0a64c7e981a012812bbca152010195cd4296d959cfa35f1e"}]',
     'merkle_root': '6d05fb9f0c2cff4942987661a44e71f0f554d435ce494dd3e7a21df6c6ba963c',
     'notarized_location': 'beta-baas',
     'object': {'eTag': '2c7c3d5f244f1a40069a32224215e0cf9b42485c99d80f357d76f006359c7a18',
                'key': '<file name>',
                'sequencer': 'DEF04BD0C5114542F8',
                'size': 446},
     'blockchain': 'eth',
     'qr_code': 'data:image/png;base64,iVBORw0KGgoAAAANSUh...',
     'sender': '0x201354729f8d0f8b64e9a0c353c672c6a66b3857',
     'signee_details': {'tenant_name': 'John Doe'},
     'timestamp': 1573572432,
     'txid': '0x6494a098f6487ebbcfa85b7cbe64c1f9f077f03866477b67be64320ea109fa73',
     'version': '3'}
    
  14. Once the notarization is complete, verify the file’s authenticity by sending a POST request with the JSON text to the /meta/verify endpoint:

    >>> response = requests.post(
    ...     f'{base_url}/meta/verify',
    ...     headers={'Content-Type': 'application/json', **auth},
    ...     data=metadata,
    ... )
    

    Note

    We do not recalculate the hash value because we assume that the file contents have not been changed.

  15. Check the status code of the response:

    >>> response.status_code
    200
    

    Status code 200 means that the request was successful.

    A different status code means that an error has occurred. For the details, refer to “Status and error codes”.

    Also, the response body contains the certificates key containing an array of notarization certificate objects formatted as a JSON text. When converted to an object, it will look as follows:

    >>> pprint.pprint(response.json())
    {'certificates': [{'id': '7605f73deaee7b071a570b3ac20cc9fe7a3abf337be7c86c55c28af9d3d8435c',
                       ...,
                       'version': '3'}]}
    

    The array in the certificates key of the response’s JSON object should contain the notarization certificate with the same ID and contents as in the previous step.

In this section