---
# System prepended metadata

title: Envelope Tags Update Post-IETF 117

---

# Current Case-Arm Discriminators

These five case-arms are critical to the base envelope specification.

```
case .node // [subject, assertion1...]

case .leaf // 24(CBOR)

case .wrapped // 200(envelope)

case .assertion // 201([predicate, object])

case .elided // bstr
```

These case-arms can be considered extensions to the base spec.

```
case .knownValue // 202(int|string)

case .encrypted // 205(encrypted)

case .compressed // 206(compressed)
```

# Analysis

* So far I've gotten rid of the need for the internal tag for elided, and for wrapped.

* Wrapped never had any use as a stand-alone tagged object, so good riddance. Downside: none.

* Elided (Digest) *does* have use as a stand-alone tagged object, but we can move it to the high 1+2 tag space, as it's only going to be used outside the context of envelope encoding. Downside: differenct encoding inside and outside envelope context.

* Known value is currently discriminated using a tag. But since it *only*be an int, we could say that ints are now *themselves* the discriminator for known value. This makes them even more compact as they won't even need a tag. Downside: different encoding inside and outside envelope context.

* Assertion also has no use outside the context of envelope encoding, so I'm thinking of changing it to a non-tag discriminator, like a single-entry map `{predicate: object}`. This only has 1-byte overhead to declare the map. Downside: none.

* I think we still need tags for `encrypted` and `compressed`. But I also think it wouldn't be bad to move them up to the high 1+2 space as well.

# Proposed New Format

These case-arms would be described in the next version of the I-D, but only one tag needs to be assigned: the master envelope tag (200).

```
case .node // [subject, assertion1...]

case .leaf // 24(CBOR)

case .wrapped // 200(envelope)

case .assertion // {predicate: object}

case .elided // bstr
```

This case does not need to be mentioned in the envelope I-D, but can be defined as an extension in another I-D. We can define its tag in the high 1+2 space, but now it doesn't need any tag at all inside an envelope.

```
case .knownValue // uint
```

These can be moved to high 1+2 tags that would meet no contest from IANA. They don't even need to be mentioned in the next version of the I-D, and could be defined in separate I-Ds.

```
case .encrypted // 205(encrypted)

case .compressed // 206(compressed)
```

These tags could be renumbered even higher, to the 1+4 first-come first-served range:

```
    static let request = Tag(207, "request")
    static let response = Tag(208, "response")
    static let function = Tag(209, "function")
    static let parameter = Tag(210, "parameter")
    static let placeholder = Tag(211, "placeholder")
    static let replacement = Tag(212, "replacement")

    static let agreementPrivateKey = Tag(301, "agreement-private-key")
    static let agreementPublicKey = Tag(302, "agreement-public-key")
    static let commonIdentifier = Tag(312, "cid")
    static let seedDigest = Tag(313, "seed-digest")
    static let nonce = Tag(314, "nonce")
    static let password = Tag(315, "password")
    static let privateKeyBase = Tag(316, "crypto-prvkeys")
    static let publicKeyBase = Tag(317, "crypto-pubkeys")
    static let salt = Tag(318, "salt")
    static let sealedMessage = Tag(319, "crypto-sealed")
    static let signature = Tag(320, "signature")
    static let signingPrivateKey = Tag(321, "signing-private-key")
    static let signingPublicKey = Tag(322, "signing-public-key")
    static let symmetricKey = Tag(323, "crypto-key")
```

The problem remains what to do about the CBOR tags that are in use but likely to be contested if we try to register them. We could

* do a hard fork, or
* adopt a transitional plan where we're accepting both these tags as legacy and a new higher tag, but only writing the new higher tag.

Obviously the hard fork is easier for us to implement. But either way, third-party developers currently using these tags may find themselves receiving constructs from us that no longer use them.

```
    static let seed = Tag(300, "crypto-seed") // Fixed
    static let ecKey = Tag(306, "crypto-eckey") // Fixed
    static let sskrShare = Tag(309, "crypto-sskr") // Fixed

    static let hdKey = Tag(303, "crypto-hdkey") // Fixed
    static let derivationPath = Tag(304, "crypto-keypath") // Fixed
    static let useInfo = Tag(305, "crypto-coin-info") // Fixed
    static let address = Tag(307, "crypto-address") // Fixed
    static let psbt = Tag(310, "crypto-psbt") // Fixed
    static let account = Tag(311, "crypto-account") // Fixed
    
    static let output = Tag(308, "crypto-output") // Fixed

    static let outputScriptHash = Tag(400, "output-script-hash") // Fixed
    static let outputWitnessScriptHash = Tag(401, "output-witness-script-hash") // Fixed
    static let outputPublicKey = Tag(402, "output-public-key") // Fixed
    static let outputPublicKeyHash = Tag(403, "output-public-key-hash") // Fixed
    static let outputWitnessPublicKeyHash = Tag(404, "output-witness-public-key-hash") // Fixed
    static let outputCombo = Tag(405, "output-combo") // Fixed
    static let outputMultisig = Tag(406, "output-multisig") // Fixed
    static let outputSortedMultisig = Tag(407, "output-sorted-multisig") // Fixed
    static let outputRawScript = Tag(408, "output-raw-script") // Fixed
    static let outputTaproot = Tag(409, "output-taproot") // Fixed
    static let outputCosigner = Tag(410, "output-cosigner") // Fixed

    static let outputDescriptorResponse = Tag(500, "output-descriptor-response") // Fixed
```