Skip to content

Commit c853f28

Browse files
committed
Apply acrolinx fixes to verify receipt article
1 parent f4daa5c commit c853f28

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

articles/confidential-ledger/verify-write-transaction-receipts.md

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ ms.topic: how-to
1313

1414
## Context
1515

16-
For more details about Azure Confidential Ledger write transaction receipts, please refer to the detailed documentation on the topic that can be found at the [following page](write-transaction-receipts.md).
16+
An Azure Confidential Ledger write transaction receipt represents a cryptographic Merkle proof that the corresponding write transaction has been globally committed by the CCF network. Azure Confidential Ledger users can get a receipt over a committed write transaction at any point in time to verify that the corresponding write operation was successfully recorded into the immutable ledger.
17+
18+
For more information about Azure Confidential Ledger write transaction receipts, see the [dedicated article](write-transaction-receipts.md).
1719

1820
## Receipt verification steps
1921

20-
An Azure Confidential Ledger write transaction receipt represents a cryptographic Merkle proof that the corresponding write transaction has been globally committed into the immutable ledger. A receipt can be verified following a specific set of steps outlined in the following sub-sections.
22+
A write transaction receipt can be verified following a specific set of steps outlined in the following subsections. The same steps are outlined in the [CCF Documentation](https://microsoft.github.io/CCF/main/use_apps/verify_tx.html#receipt-verification).
2123

2224
### Leaf node computation
2325

@@ -27,13 +29,13 @@ The first step is to compute the SHA-256 hash of the leaf node in the Merkle Tre
2729
2. SHA-256 digest of `commit_evidence`
2830
3. `claims_digest` fields
2931

30-
Please keep in mind that the these values needs to be concatenated as arrays of bytes. This means that `write_set_digest` and `claims_digest` would need to be converted from strings of hexadecimal digits to arrays of bytes; on the other hand, the hash of `commit_evidence` can be obtained by applying the SHA-256 hash function over the UTF-8 encoded `commit_evidence` string.
32+
These values need to be concatenated as arrays of bytes: both `write_set_digest` and `claims_digest` would need to be converted from strings of hexadecimal digits to arrays of bytes; on the other hand, the hash of `commit_evidence` (as an array of bytes) can be obtained by applying the SHA-256 hash function over the UTF-8 encoded `commit_evidence` string.
3133

3234
Similarly, the leaf node hash digest can be computed by applying the SHA-256 hash function over the result concatenation of the resulting bytes.
3335

3436
### Root node computation
3537

36-
The second step is to compute the SHA-256 hash of the root of the Merkle Tree at the time the transaction was committed. This can be accomplished by iteratively concatenating and hashing the result of the previous iteration (starting from the leaf node hash computed in the previous step) with the ordered nodes' hashes provided in the `proof` field of a receipt. Please note that the `proof` list is provided as an ordered list and its elements need to be iterated in the given order.
38+
The second step is to compute the SHA-256 hash of the root of the Merkle Tree at the time the transaction was committed. The computation is done by iteratively concatenating and hashing the result of the previous iteration (starting from the leaf node hash computed in the previous step) with the ordered nodes' hashes provided in the `proof` field of a receipt. The `proof` list is provided as an ordered list and its elements need to be iterated in the given order.
3739

3840
The concatenation needs to be done on the bytes representation with respect to the relative order indicated in the objects provided in the `proof` field (either `left` or `right`).
3941

@@ -48,20 +50,21 @@ The third step is to verify that the cryptographic signature produced over the r
4850

4951
1. Decode the base64 string `signature` into an array of bytes.
5052
2. Extract the ECDSA public key from the signing node certificate `cert`.
51-
3. Verify that the signature over the root of the Merkle Tree (computed using the instructions in the previous sub-section) is authentic using the extracted public key from the previous step. This step effectively corresponds to a standard [digital signature](https://wikipedia.org/wiki/Digital_signature) verification process using ECDSA. There are many libraries in the most popular programming languages that allow verifying an ECDSA signature using a public key certificate over some data and that can be leveraged for this step (e.g., [ecdsa](https://pypi.org/project/ecdsa/) for Python).
53+
3. Verify that the signature over the root of the Merkle Tree (computed using the instructions in the previous subsection) is authentic using the extracted public key from the previous step. This step effectively corresponds to a standard [digital signature](https://wikipedia.org/wiki/Digital_signature) verification process using ECDSA. There are many libraries in the most popular programming languages that allow verifying an ECDSA signature using a public key certificate over some data (for example, [ecdsa](https://pypi.org/project/ecdsa/) for Python).
5254

5355
### Verify signing node certificate endorsement
5456

55-
In addition to the above, it is also required to verify that the signing node certificate is endorsed (i.e., signed) by the current ledger certificate. Please note that this step does not depend on the other three previous steps and can be carried out independenly from the others.
57+
In addition to the above, it's also required to verify that the signing node certificate is endorsed (that is, signed) by the current ledger certificate. This step doesn't depend on the other three previous steps and can be carried out independently from the others.
5658

57-
As the ledger certificate may have been renewed since the transaction was committed, it is possible that the current service identity that issued the receipt is different from the one that endorsed the signing node. If this applies, it is required to verify the chain of certificates trust from the signing node certificate (i.e., the `cert` field in the receipt) up to the trusted root Certificate Authority (CA) (i.e., the current service identity certificate) through other previous service identities (i.e., the `service_endorsements` list field in the receipt). Please note that the `service_endorsements` list is provided as an ordered list from the oldest to the latest service identity.
59+
It's possible that the current service identity that issued the receipt is different from the one that endorsed the signing node (for example, due to a certificate renewal). In this case, it's required to verify the chain of certificates trust from the signing node certificate (that is, the `cert` field in the receipt) up to the trusted root Certificate Authority (CA) (that is, the current service identity certificate) through other previous service identities (that is, the `service_endorsements` list field in the receipt). The `service_endorsements` list is provided as an ordered list from the oldest to the latest service identity.
5860

59-
Certificate endorsement need to be verified for the entire chain and follows the exact same digital signature verification process outlined in the previous sub-section. There are popular open-source cryptographic libraries (e.g., [OpenSSL](https://www.openssl.org/)) that can be typically used to carry out a certificate endorsement step.
61+
Certificate endorsement need to be verified for the entire chain and follows the exact same digital signature verification process outlined in the previous subsection. There are popular open-source cryptographic libraries (for example, [OpenSSL](https://www.openssl.org/)) that can be typically used to carry out a certificate endorsement step.
6062

61-
### Additional resources
63+
### More resources
6264

63-
Please refer to the [CCF documentation about receipt verification](https://microsoft.github.io/CCF/main/use_apps/verify_tx.html#receipt-verification) for more details about how the algorithm works. The following links could also be useful to better understand some topics related to receipt verification:
65+
For more information about the content of an Azure Confidential Ledger write transaction receipt and explanation of each field, see the [dedicated article](write-transaction-receipts.md#write-transaction-receipt-content). The [CCF documentation](https://microsoft.github.io/CCF) also contains more information about receipt verification and other related resources at the following links:
6466

67+
* [Receipt Verification](https://microsoft.github.io/CCF/main/use_apps/verify_tx.html#receipt-verification)
6568
* [CCF Glossary](https://microsoft.github.io/CCF/main/overview/glossary.html)
6669
* [Merkle Tree](https://microsoft.github.io/CCF/main/architecture/merkle_tree.html)
6770
* [Cryptography](https://microsoft.github.io/CCF/main/architecture/cryptography.html)
@@ -73,13 +76,13 @@ Please refer to the [CCF documentation about receipt verification](https://micro
7376

7477
For reference purposes, we provide sample code in Python to fully verify Azure Confidential Ledger write transaction receipts following the steps outlined above.
7578

76-
For the verification algorithm, we are going to need the current service network certificate and a write transaction receipt from a running Confidential Ledger resource. Please refer to the [following page](write-transaction-receipts.md#fetching-a-write-transaction-receipt) for details on how to fetch a write transaction receipt and how to retrieve the service certificate.
79+
To run the full verification algorithm, the current service network certificate and a write transaction receipt from a running Confidential Ledger resource are required. Refer to [this article](write-transaction-receipts.md#fetching-a-write-transaction-receipt) for details on how to fetch a write transaction receipt and the service certificate from a Confidential Ledger instance.
7780

7881
### Code walkthrough
7982

80-
We are going to use a separate utility (`verify_receipt`) to run the receipt verification algorithm and we provide as input of the algorithm the content of the `receipt` field of a `GET_RECEIPT` response as a dictionary and the service certitificate as a simple string. The function throws an exceptions if the receipt is not valid or if any error was encountered.
83+
The following code can be used to initialize the required objects and run the receipt verification algorithm. A separate utility (`verify_receipt`) is used to run the full verification algorithm, and accepts input the content of the `receipt` field in a `GET_RECEIPT` response as a dictionary and the service certificate as a simple string. The function throws an exception if the receipt isn't valid or if any error was encountered during the processing.
8184

82-
We assume that both the receipt and the service certificate can be loaded from files.
85+
It's assumed that both the receipt and the service certificate can be loaded from files. Make sure to update both the `service_certificate_file_name` and `receipt_file_name` constants with the respective files names of the service certificate and receipt you would like to verify.
8386

8487
```python
8588
import json
@@ -108,10 +111,10 @@ with open(service_certificate_file_name, "r") as service_certificate_file, open(
108111
        raise e
109112
```
110113

111-
As the verification process requires some cryptographic and hashing algorithms, we are going to need the following modules as helper utilities:
114+
As the verification process requires some cryptographic and hashing primitives, the following libraries are used to facilitate the computation.
112115

113116
* The [CCF Python library](https://microsoft.github.io/CCF/main/audit/python_library.html): the module provides a set of tools for receipt verification.
114-
* The [Python cryptography library](https://cryptography.io/en/latest/): a widely used library that includes a variety of cryptographic algorithms and primitives.
117+
* The [Python cryptography library](https://cryptography.io/en/latest/): a widely used library that includes various cryptographic algorithms and primitives.
115118
* The [hashlib module](https://docs.python.org/3/library/hashlib.html), part of the Python standard library: a module that provides a common interface for popular hashing algorithms.
116119

117120
```python
@@ -136,7 +139,7 @@ assert "service_endorsements" in receipt
136139
assert "signature" in receipt
137140
```
138141

139-
We initialize the variables we are going to use for the rest of the program.
142+
We initialize the variables that are going to be used in the rest of the program.
140143

141144
```python
142145
# Set the variables
@@ -150,7 +153,7 @@ service_endorsements_certs_pem = receipt["service_endorsements"]
150153
root_node_signature = receipt["signature"]
151154
```
152155

153-
We check that the receipt is not related to a signature transaction. Receipts for signature transactions are not allowed for Confidential Ledger.
156+
In the following snipper, we check that the receipt isn't related to a signature transaction. Receipts for signature transactions aren't allowed for Confidential Ledger.
154157

155158
```python
156159
# Check that this receipt is not for a signature transaction
@@ -182,7 +185,7 @@ leaf_node_hex = compute_leaf_node(
182185

183186
The `compute_leaf_node` function accepts as parameters the leaf components of the receipt (the `claims_digest`, the `commit_evidence`, and the `write_set_digest`) and returns the leaf node hash in hexadecimal form.
184187

185-
As detailed above, we compute the digest of `commit_evidence` (using the SHA256 hashlib function). Then, we convert both `write_set_digest` and `claims_digest` into arrays of bytes. Finally, we concatenate the three arrays, and we digest the result using the SHA256 hashlib function.
188+
As detailed above, we compute the digest of `commit_evidence` (using the SHA256 `hashlib` function). Then, we convert both `write_set_digest` and `claims_digest` into arrays of bytes. Finally, we concatenate the three arrays, and we digest the result using the SHA256 function.
186189

187190
```python
188191
def compute_leaf_node(
@@ -220,7 +223,7 @@ After computing the leaf, we can compute the root of the Merkle tree.
220223
root_node = root(leaf_node_hex, proof_list)
221224
```
222225

223-
We leverage the function `root` provided as part of the CCF Python library. The function successively concatenates the result of the previous iteration with a new element from `proof`, digests the concatenation, and then repeats the step for every element in `proof` with the previously computed digest. The concatenation needs to respect the order of the nodes in the Merkle Tree to make sure the root is re-computed correctly.
226+
We use the function `root` provided as part of the CCF Python library. The function successively concatenates the result of the previous iteration with a new element from `proof`, digests the concatenation, and then repeats the step for every element in `proof` with the previously computed digest. The concatenation needs to respect the order of the nodes in the Merkle Tree to make sure the root is recomputed correctly.
224227

225228
```python
226229
def root(leaf: str, proof: List[dict]):
@@ -271,7 +274,7 @@ The last step of receipt verification is validating the certificate that was use
271274
check_endorsements(node_cert, service_cert, service_endorsements_certs)
272275
```
273276

274-
Likewise, we can use the CCF utility `check_endorsements` to validate that the certificate of the signing node is endorsed by the service identity. The certificate chain could be composed of previous service certificates, so we should validate that the endorsement is applied transitively if `service_endorsements` is not an empty list.
277+
Likewise, we can use the CCF utility `check_endorsements` to validate that the certificate of the signing node is endorsed by the service identity. The certificate chain could be composed of previous service certificates, so we should validate that the endorsement is applied transitively if `service_endorsements` isn't an empty list.
275278

276279
```python
277280
def check_endorsement(endorsee: Certificate, endorser: Certificate):
@@ -304,7 +307,7 @@ def check_endorsements(
304307
    check_endorsement(cert_i, service_cert)
305308
```
306309

307-
As an alternative, we could also validate the certificate by leveraging the OpenSSL library using a similar method.
310+
As an alternative, we could also validate the certificate by using the OpenSSL library using a similar method.
308311

309312
```python
310313
from OpenSSL.crypto import (
@@ -503,5 +506,6 @@ def verify_openssl_certificate(
503506

504507
## Next steps
505508

509+
* [Azure Confidential Ledger write transaction receipts](write-transaction-receipts.md)
506510
* [Overview of Microsoft Azure confidential ledger](overview.md)
507511
* [Azure confidential ledger architecture](architecture.md)

0 commit comments

Comments
 (0)