Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfmcnally committed Feb 27, 2024
2 parents f51a99e + 45f6f21 commit daeeff3
Show file tree
Hide file tree
Showing 2 changed files with 318 additions and 1 deletion.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Each BCR has a status which is indicated by a symbol.
| ⭐️⭐️ | Multiple Implementations | At least two (known) implementations exist, at least one not by the owner of the reference implementation. Has demonstrable community support. May still change due to the needs of the community, but community feedback will be sought.
| ⭐️⭐️⭐️ | Standards Track | Typically at least two implementations, and is considered stable and ready for standardization. Being proposed as a BIP, IETF Internet Draft, or some other standardization draft format. Will typically be moved to the [BCP repo](https://github.com/BlockchainCommons/bcps). Though changes may still be made to the specification, these changes will exclusively be to allow for standardization, and will be conducted with community feedback.
| ⭐️⭐️⭐️⭐️ | Standardized | A specification has been standardized as a an IETF RFC, BIP, or approved by some other standards body.
| 📖 | Implementation Guide | A developer's guide to implementating a specification that may also double as the specification itself. |

❌❌ after another status symbol is read, "...but withdrawn" and ❌ is read, "...but superseded".

Expand Down Expand Up @@ -68,9 +69,10 @@ Each BCR has a status which is indicated by a symbol.
| [BCR-2023-017](papers/bcr-2023-017-salt.md) | UR Type Definition for Random Salt | Wolf McNally | ⭐️ |
| [BCR-2023-018](papers/bcr-2023-018-depo-api.md) | Gordian Depository API | Wolf McNally | ⭐️ |
| [BCR-2023-019](papers/bcr-2023-019-account-descriptor.md) | UR Type Definition for BIP44 Accounts (Version 2) | Craig Raw | ⭐️⭐️ |
| [BCR-2024-001](papers/bcr-2024-001-multipart-ur.md) | Multipart UR (MUR) Implementation Guide | Wolf McNally | ⭐️⭐️ |
| [BCR-2024-001](papers/bcr-2024-001-multipart-ur.md) | Multipart UR (MUR) Implementation Guide | Wolf McNally | 📖⭐️⭐️ |
| [BCR-2024-002](papers/bcr-2024-002-dcbor.md) | dCBOR: A Deterministic CBOR Application Profile | Wolf McNally | ⭐️⭐️⭐️ |
| [BCR-2024-003](papers/bcr-2024-003-envelope.md) | The Gordian Envelope Structured Data Format | Wolf McNally | ⭐️ |
| [BCR-2024-004](papers/bcr-2024-004-request.md) | Envelope Request & Response Implementation Guide | Shannon Appelcline | 📖⭐️ |

_Also see our [Testimony](https://github.com/BlockchainCommons/Testimony/blob/master/README.md) and our [Blockchain Commons Proposals](https://github.com/BlockchainCommons/bcps/blob/master/README.md)._

Expand Down
315 changes: 315 additions & 0 deletions papers/bcr-2024-004-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
# Envelope Request & Response Implementation Guide 📖

Implementer's guide for the Request & Response Expressions in Gordian Envelope.

## BCR-2024-004

**© 2024 Blockchain Commons**

Authors: Shannon Appelcline, Wolf McNally, Christopher Allen<br/>
Date: February 20, 2024

---

## Table of Contents

1. [Introduction](#1-introduction)
2. [Expressions](#2-expressions-the-foundation-of-request--response)
3. [GSTP](#3-gordian-secure-transport-protocol-wrapping-a-request)
4. [Putting It Together](#4-putting-it-together)

## 1. Introduction

[Gordian Envelope](https://developer.blockchaincommons.com/envelope/) includes request and response functionality: one user can issue an Envelope requesting certain information or certain actions and then another user can respond to that request with the data.

Request and response are crucial for enabling interoperability and thus interactions between different members of a digital-asset ecosystem. The two largest use cases for Request and Response are currently: seed vaults talking to transaction coordinators (for example if Gordian Seed Tool wants to talk to Sparrow); and seed vaults talking to share servers (for example if Gordian Seed Tool wants to talk to Gordian Depo).

**Example Seed Vault (SV) ⇔ Network Coordinator (NC) Interactions**

* **NC Request:** Seed Digest
* **SV Response:** Specific Seed
* **NC Request:** Key Identifier
* **SV Reponse:** Specific Key
* **NC Request:** Key-Derivation Path
* **SV Response:** Specific Key
* **NC Request:** Unsigned PSBT
* **SV Response:** Signed PSBT

**Example Seed Vault (SV) ⇔ Share Server (SS) Interactions**

* **SV Request:** Share with Receipt
* **SS Response:** Specific Share
* **SV Request:** Shares
* **SS Response:** All Shares

A Request/Response system helps to reduce the complexity of these digital tasks. A user may not be able to find a specific seed or to generate a key along an appropriate derivation path without guidance. A Request/Response system provides that guidance to minimize errors and user frustration alike.

A Request/Response system becomes even more important as tasks are combined together for more complex projects. The [multisig self-sovereign scenario](https://github.com/BlockchainCommons/SmartCustody/blob/master/Docs/Scenario-Multisig.md) is one such example. It demonstrates how to safely secure digital assets using keys on two closely held devices. However, it is too complex for more users. A system built on Requests and Responses that told users what to do as part of an interactive process would be more likely to be successful.

## 2. Expressions: The Foundation of Request & Response

Requests and Responses are built atop an Envelope functionality called [Expressions](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2023-012-envelope-expression.md). Expressions are essentially functions. They take the following form within a Gordian Envelope:

```
«function» [
❰parameter❱: argument
❰parameter❱: argument
...
]
```
The function is the Envelope subject. Envelope assertions then each define a paired parameter and argument for that function.

A function to retrieve a seed looks as follows:
```
«100» [
❰200❱: Digest(ffa11a8b)
]
```

The numbers refer to specific functions and specific parameters. They are essentially "known values" for Envelope Expressions. These values are defined in [Format.swift](https://github.com/BlockchainCommons/BCSwiftEnvelope/blob/master/Sources/Envelope/Base/Format.swift) in the [Envelope base code](https://github.com/BlockchainCommons/BCSwiftEnvelope/tree/master/Sources/Envelope/Base).

The function call is tagged with CBOR tag #40006, which defines it as a `ur:function` and the parameter is defined with CBOR tag #40007, which defines it as a `ur:parameter`. This is represented in `envelope-cli` (and in the examples here) with "«»" for `ur:function` and "❰❱" for `ur:parameter`.

The `ur:function` values are as follows:

| # | Function | Expected Response |
|---|----------|-----------------|
| 100 | getSeed | isA: Seed (200) |
| 101 | getKey | isA: PrivateKey (201) AND/OR<br>isA: PublicKey (202) AND/OR<br>isA MasterKey (203) AND/OR<br>isA BIP32Key (500) |
| 102 | signPSBT | isA: PSBT (506) |
| 103 | getOutputDescriptor | isA: OutputDescriptor (507) |

The `ur:parameter` values are as follows:

| # | Parameter |
|----|----------|
| 200 | seedDigest |
| 201 | derivationPath |
| 202 | isPrivate |
| 203 | useInfo |
| 204 | isDerivable |
| 205 | psbt |
| 206 | name |
| 207 | challenge |

The above function to retrieve a seed thus parses as follows:
```
«getSeed» [
❰seedDigest❱: Digest(ffa11a8b)
]
```

In other words, that's a Request to send a seed that matches the digest `ffa11a8b...`

### Responses to Function Requests

Though Requests contain functions (Expressions), Responses are just standard Envelopes. A Response MUST contain the requested object as the subject of an Envelope and that subject MUST contain at least one assertion of the form 'isA: [object type]'. It MAY contain other assertions.

Here's an example of a Response to the `«getSeed»` function for `ffa11a8b`.

```
Bytes(16) [
1: 200
11: "Dark Purple Peck Vial"
507: output-descriptor(Map)
]
```

The subject is the seed, while the three assertions describe the seed. The subjects of those assertions are all [known values](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2023-002-known-value.md) (as is the object of the first assertion). They can be read as follows:

```
Bytes(16) [
'isA': 'Seed'
'hasName': "Dark Purple Peck Vial"
'outputDescriptor': output-descriptor(Map)
]
```

The `isA` assertion is the required one. The others are optional.

The output descriptor contains a map structure as described in [BCR-2023-010](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2023-010-output-descriptor.md).

## 3. Gordian Secure Transport Protocol: Wrapping a Request

To make a Request requires wrapping an Expression with a `ur:request` subject. This is done using the methodology of [Gordian Secure Transport Protocol (GSTP)](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2023-014-gstp.md).

(Note that the overall GSTP protocol includes encryption & signature steps, which are certainly best practices for Requests and Responses, but not required. The following describes only the Request and Reponses Envelopes, which are also enclosed in GSTP communications, but which can alternatively be standalone in other uses of `request` and `response`.)

Creating the subject for a Request requires the following steps:

1. Generate an ["Apparently Random Identifier"](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2022-002-arid.md).
2. Tag it as `ur:arid` (CBOR tag #40012).
3. Tag that as `request` (CBOR tag #40004).

`envelope-cli` will display a Request subject as follows:
```
request(ARID(7b33b86e))
```
The actual CBOR looks like this:
```
40004(40012(
h'7b33b86e604e3cb5ef9d1675d59c70b6ea7d1f625d062e4d14c4310f2e616cd9'
))
```

Creating the object for a Request requires the following addition steps:

4. Create an assertion with a subject of `body` (known value #100).
5. Make your Request Expression the object of that assertion.
6. Optionally create a `note` (known value #4) about the Request as an additional assertion.
7. Optionally create other info as additional assertions.

Putting that all together, here's a complete `request` containing the `«getSeed»` function call shown above:

```
request(ARID(7b33b86e)) [
100: «100» [
❰200❱: Digest(ffa11a8b)
]
4: "Alias quam ullam qui reprehenderit ad quibusdam in hic occaecati aut ut voluptas dicta eligendi nobis. Molestiae neque voluptatibus et dolor qui quas?"
]
```

Here it is with all the known values and function values filled in:

```
request(ARID(7b33b86e)) [
'body': «getSeed» [
❰seedDigest❱: Digest(ffa11a8b)
]
'note': "Alias quam ullam qui reprehenderit ad quibusdam in hic occaecati aut ut voluptas dicta eligendi nobis. Molestiae neque voluptatibus et dolor qui quas?"
]
```

Digging down instead, here's what the lower-level CBOR of that Request looks like:
```
[
24(40004(40012(
h'7b33b86e604e3cb5ef9d1675d59c70b6ea7d1f625d062e4d14c4310f2e616cd9'
))),
{4: 24("Alias quam ullam qui reprehenderit ad quibusdam in hic occaecati aut ut voluptas dicta eligendi nobis. Molestiae neque voluptatibus et dolor qui quas?")},
{100: [
24(40006(100)),
{24(40007(200)): 24(40001(
h'ffa11a8b90954fc89ae625779ca11b8f0227573a2f8b4ed85d96ddf901a72cea'
))}
]
}
]
```
Here's a more detailed look at the CBOR for this `request`:
```
/* Array of 3 */
[
/* #1: request(ARID(7b33b86e)) */
/* CBOR tag #24 = byte string */
/* CBOR tag #40004 = request */
/* CBOR tag #40012 = ur:arid */
24(40004(40012(
h'7b33b86e604e3cb5ef9d1675d59c70b6ea7d1f625d062e4d14c4310f2e616cd9'
))),
/* #2: note */
/* map */
/* Known Value #4 = note */
/* CBOR tag #24 = byte string */
{4: 24("Alias quam ullam qui reprehenderit ad quibusdam in hic occaecati aut ut voluptas dicta eligendi nobis. Molestiae neque voluptatibus et dolor qui quas?")},
/* #3: 'body': «getSeed» */
/* map */
/* Known Value #100 = body */
/* array of 2 */
/* CBOR tag #24 = bytestring */
/* CBOR tag #40006 = ur:function */
/* Function #100 = getSeed */
/* CBOR tag #24 = bytestring */
/* CBOR tag #40007 = ur:parameter */
/* Parameter #200 = seedDigest */
/* CBOR tag #24 = bytestring */
/* CBOR tag #40001 = ur:digest */
{100: [
24(40006(100)),
{24(40007(200)): 24(40001(
h'ffa11a8b90954fc89ae625779ca11b8f0227573a2f8b4ed85d96ddf901a72cea'
))}
]
}
]
```
### Responses to GSTP Requests

To respond to a GSTP Request:

1. Create a subject with the _same_ ARID as the Request.
2. Tag it as `ur:arid` (CBOR tag #40012).
3. Tag that as `response` (CBOR tag #40005).
4. Create an object with a 'result' subject (known value #101).
5. Add an object to the 'result' subject containing the Requested data.
6. Create an assertion under the 'result' assertions that contains 'isA:' and the appropriate data type.
7. Add additional assertions with any other metadata desired.

The response to the above request thus look as follows:

```
response(ARID(7b33b86e)) [
101: Bytes(16) [
1: 200
11: "Dark Purple Peck Vial"
507: output-descriptor(Map)
]
]
```

Or:
```
response(ARID(7b33b86e)) [
'result': Bytes(16) [
'isA': 'Seed'
'hasName': "Dark Purple Peck Vial"
'outputDescriptor': output-descriptor(Map)
]
]
```

### 4. Putting It Together

Here's the complete `request` and `response` examples from above.

```
request(ARID(7b33b86e)) [
'body': «getSeed» [
❰seedDigest❱: Digest(ffa11a8b)
]
'note': "Alias quam ullam qui reprehenderit ad quibusdam in hic occaecati aut ut voluptas dicta eligendi nobis. Molestiae neque voluptatibus et dolor qui quas?"
]
```

```
response(ARID(7b33b86e)) [
'result': Bytes(16) [
'isA': 'Seed'
'hasName': "Dark Purple Peck Vial"
'outputDescriptor': output-descriptor(Map)
]
]
```

Complete test vectors can be found at [Envelope Request & Response Test Vectors](https://developer.blockchaincommons.com/envelope/request/vectors/).

0 comments on commit daeeff3

Please sign in to comment.