# 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 ```