Skip to main content

Selective Merkle Disclosure CBOR Web Tokens (SMD-CWT)
draft-maldant-spice-smd-cwt-00

Document Type Active Internet-Draft (individual)
Author Beltram Maldant
Last updated 2026-10-26
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-maldant-spice-smd-cwt-00
Secure Patterns for Internet CrEdentials                      B. Maldant
Internet-Draft                                               SimpleLogin
Intended status: Standards Track                         26 October 2026
Expires: 29 April 2027

         Selective Merkle Disclosure CBOR Web Tokens (SMD-CWT)
                     draft-maldant-spice-smd-cwt-00

Abstract

   This document specifies an extension to Selective Disclosure CBOR Web
   Tokens (SD-CWT) that reduces their size and improves their privacy
   properties.  In this extension, the individual hashes of the redacted
   claims of a map or an array are replaced with the root hash of a
   Merkle tree, and disclosed claims are presented with a Merkle proof.

About This Document

   This note is to be removed before publishing as an RFC.

   The latest revision of this draft can be found at
   https://beltram.github.io/draft-maldant-spice-smd-cwt/draft-maldant-
   spice-smd-cwt.html.  Status information for this document may be
   found at https://datatracker.ietf.org/doc/draft-maldant-spice-smd-
   cwt/.

   Discussion of this document takes place on the Secure Patterns for
   Internet CrEdentials Working Group mailing list
   (mailto:spice@ietf.org), which is archived at
   https://mailarchive.ietf.org/arch/browse/spice/.  Subscribe at
   https://www.ietf.org/mailman/listinfo/spice/.

   Source for this draft and an issue tracker can be found at
   https://github.com/beltram/draft-maldant-spice-smd-cwt.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

Maldant                   Expires 29 April 2027                 [Page 1]
Internet-Draft                   SMD-CWT                    October 2026

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 29 April 2027.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.  Code Components
   extracted from this document must include Revised BSD License text as
   described in Section 4.e of the Trust Legal Provisions and are
   provided without warranty as described in the Revised BSD License.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
   2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   3
   3.  Overview  . . . . . . . . . . . . . . . . . . . . . . . . . .   4
   4.  Issuance  . . . . . . . . . . . . . . . . . . . . . . . . . .   4
     4.1.  Pre-Issuance  . . . . . . . . . . . . . . . . . . . . . .   5
     4.2.  Merkle Tree . . . . . . . . . . . . . . . . . . . . . . .   6
       4.2.1.  Decoys  . . . . . . . . . . . . . . . . . . . . . . .   7
     4.3.  Computing the Merkle Root Hash  . . . . . . . . . . . . .   8
       4.3.1.  Inserting the Merkle Root Hash in the Payload . . . .   8
     4.4.  Disclosure  . . . . . . . . . . . . . . . . . . . . . . .   9
     4.5.  Content-Type  . . . . . . . . . . . . . . . . . . . . . .  13
   5.  Presentation  . . . . . . . . . . . . . . . . . . . . . . . .  13
   6.  Verification  . . . . . . . . . . . . . . . . . . . . . . . .  16
   7.  Benefits over SD-CWT  . . . . . . . . . . . . . . . . . . . .  18
     7.1.  Smaller Tokens  . . . . . . . . . . . . . . . . . . . . .  18
     7.2.  Privacy . . . . . . . . . . . . . . . . . . . . . . . . .  18
     7.3.  Free Decoys . . . . . . . . . . . . . . . . . . . . . . .  19
     7.4.  Verification Time . . . . . . . . . . . . . . . . . . . .  19
   8.  Privacy Considerations  . . . . . . . . . . . . . . . . . . .  19
     8.1.  Leakage of Claim Order  . . . . . . . . . . . . . . . . .  19
   9.  Security Considerations . . . . . . . . . . . . . . . . . . .  19
   10. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  19
     10.1.  CBOR Tags  . . . . . . . . . . . . . . . . . . . . . . .  19
       10.1.1.  To Be Redacted Root Tag  . . . . . . . . . . . . . .  19
     10.2.  Media Types  . . . . . . . . . . . . . . . . . . . . . .  20

Maldant                   Expires 29 April 2027                 [Page 2]
Internet-Draft                   SMD-CWT                    October 2026

       10.2.1.  application/smd-cwt+sd-cwt . . . . . . . . . . . . .  20
       10.2.2.  application/smd-kbt+sd-kbt . . . . . . . . . . . . .  21
   11. References  . . . . . . . . . . . . . . . . . . . . . . . . .  22
     11.1.  Normative References . . . . . . . . . . . . . . . . . .  22
     11.2.  Informative References . . . . . . . . . . . . . . . . .  23
   Appendix A.  Complete CDDL Schema . . . . . . . . . . . . . . . .  23
   Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . .  25
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  25

1.  Introduction

   This document defines Selective Merkle Disclosure CBOR Web Tokens
   (SMD-CWT), an extension to SD-CWT [SD-CWT].

   SD-CWT provides an efficient mechanism by which a Holder controls
   which claims it presents to a Verifier, thereby improving the privacy
   of the Holder.  However, when the presentation is sparse and only a
   subset of the claims is disclosed, a Verifier learns the total number
   of claims, reducing the privacy benefit of selective disclosure.
   Furthermore, each redacted claim adds 34 bytes to the presented token
   (SD-KBT), even though the claim itself is not disclosed to the
   Verifier.

   To address both issues, this document specifies that, rather than
   hashing each claim individually and placing the resulting hashes in a
   CBOR array, the claims of each map or array are placed in a Merkle
   tree and only the root hash of that tree is included in the SD-CWT.
   A presentation of the token then includes only a Merkle proof
   attesting to the integrity of the disclosed claims.  The size of this
   proof is logarithmic in the number of claims, whereas the size of an
   enumeration of all redacted claims is linear in that number.

2.  Terminology

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in
   BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
   capitals, as shown here.

   The CBOR examples in this document are shown in CBOR Extended
   Diagnostic Notation (EDN) [I-D.ietf-cbor-edn-literals].

   Data model constraints are described using the Concise Data
   Definition Language (CDDL) [RFC8610].

   This document uses terms from CWT [RFC8392], COSE [RFC9052]
   [RFC9053], and JWT [RFC7519].

Maldant                   Expires 29 April 2027                 [Page 3]
Internet-Draft                   SMD-CWT                    October 2026

   The terms Claim Name, Claim Key, and Claim Value are defined in
   [RFC8392].

   This document defines the following terms:

   Selective Merkle Disclosure CBOR Web Token (SMD-CWT):  An SD-CWT
      containing claims that can be selectively disclosed using a Merkle
      proof.

   Selective Merkle Disclosure Key Binding Token (SMD-KBT):  An SD-KBT
      used to demonstrate possession of a confirmation method and to
      present claims with a Merkle proof.

   Copath:  For a given leaf of a Merkle tree, the siblings of the nodes
      on the path from that leaf to the root.

   All other terms used in this document have the meaning defined in
   [SD-CWT].

3.  Overview

   SMD-CWT is an extension of SD-CWT: every SD-CWT is a valid SMD-CWT,
   but an SMD-CWT is not necessarily a valid SD-CWT.  The two differ
   only in the way redacted claims are authenticated and presented.

   An SD-CWT Issuer enumerates the hashes of all redacted claims, either
   in the redacted_claim_keys array of a map, or in place of the
   redacted elements of an array.  In contrast, an SMD-CWT Issuer places
   these hashes at the leaves of a left-balanced Merkle tree and
   replaces the set of claims in the original payload with the root hash
   of that tree.

   A Holder then selectively presents claims to a Verifier in an SMD-KBT
   by replacing the disclosed claims with proofs of their inclusion in
   the Merkle tree.  The root hash of that tree is authenticated by the
   Issuer in the SMD-CWT.

4.  Issuance

   An SMD-CWT Issuer is also an SD-CWT Issuer: it MUST be capable of
   encoding and signing a regular SD-CWT when requested and, in
   addition, supports the generation of SMD-CWTs.

   Figure 1 shows an example CWT payload.  Common claims are omitted for
   brevity.

Maldant                   Expires 29 April 2027                 [Page 4]
Internet-Draft                   SMD-CWT                    October 2026

   {
       "most_recent_inspection_passed": true,
       "inspector_license_number": "ABCD-123456",
       "inspection_dates" : [
           1549560720,   / 2019-02-07T17:32:00 /
           1612498440,   / 2021-02-04T20:14:00 /
           1674004740,   / 2023-01-17T17:19:00 /
       ],
       "inspection_location": {
           "country": "us",            / United States /
           "region": "ca",             / California /
           "postal_code": "94188"
       }
   }

                          Figure 1: CWT Claims Set

4.1.  Pre-Issuance

   An SMD-CWT Issuer MUST support the To Be Redacted Tag and the To Be
   Decoy Tag, both of which are defined in Section 17.3.1 of [SD-CWT].

   The To Be Redacted Root Tag (tag 59), defined in Section 10.1.1,
   indicates to the Issuer that a claim or an array element is intended
   to be selectively disclosed with a Disclosure Proof.  This tag wraps
   the element to be redacted in an array of size 2.  The first element
   of this array is the base-2 logarithm of the size of the Merkle tree
   used for redaction.  This size MAY be greater than the number of
   claims to redact, but MUST NOT be lower.

   Figure 2 shows the example payload with the corresponding
   annotations.

   59([3, { /merkle-redacted of size 8/
       "most_recent_inspection_passed": true, /not-redacted/
       "inspector_license_number": 58("ABCD-123456"), /redacted/
       59([3, "inspection_dates"]) : [ /merkle-redacted of size 8/
           58(1549560720), /redacted/
           58(1612498440), /redacted/
           58(1674004740), /redacted/
       ],
       59([2, "inspection_location"]): { /merkle-redacted of size 4/
           "country": 58("us"),   /redacted/
           "region": 58("ca"),    /redacted/
           "postal_code": "94188" /not-redacted/
       }
   }])

Maldant                   Expires 29 April 2027                 [Page 5]
Internet-Draft                   SMD-CWT                    October 2026

                  Figure 2: CWT Claims Set Before Issuance

   For each occurrence of the To Be Redacted Root Tag, at any nesting
   level, a Merkle tree is built, and all elements of the tagged array
   or map are placed at its leaves.

4.2.  Merkle Tree

   This specification uses binary Merkle trees similar to those defined
   in Section 2.1.1 of [RFC9162], with one difference: no domain
   separation prefix is added to the leaves and the nodes (see
   Section 4.3).  A higher branching factor would provide neither
   additional benefit nor the desired properties.

   The Merkle tree is a left-balanced perfect binary tree, as shown in
   Figure 3.  Unbalanced trees are not used, as they are vulnerable to
   forgery attacks.  Perfect binary trees are also easier to represent
   in memory, and their node indexes are easier to compute, as explained
   in Appendix C of [RFC9420].

                 root
                  |
              .---+---.
             /         \
      h(h(A)||h(B))    h(h(C)||h(d))
           / \         / \
          /   \       /   \
       h(A)   h(B)  h(C)  h(d)
         |     |     |     |
         |     |     |     |
         A     B     C    d

   Node: 0  1  2  3  4  5  6

   Leaf: 0     1     2     3

                      Figure 3: A 3-Claim Merkle Tree

   In Figure 2, the redaction of the "inspection_location" claim places
   the "country" claim at node index 0 and the "region" claim at node
   index 2.  Since a size of 2 is requested, the tree has a height of 2
   and its last node index is 6, as in Figure 3.

Maldant                   Expires 29 April 2027                 [Page 6]
Internet-Draft                   SMD-CWT                    October 2026

4.2.1.  Decoys

   Decoys serve a different purpose than in SD-CWT: they do not directly
   hinder the Verifier's inference of private information.  Instead,
   they act as a blinding factor that prevents a Verifier from inferring
   the number of leaves, since the hash of a blank leaf is the hash of
   zero bytes.  Decoys are therefore mandatory.

   Replacing every blank leaf with a Decoy would needlessly inflate the
   SMD-CWT.  Instead, for each node in the Copath of the rightmost
   entry, the leftmost blank leaf of the subtree rooted at that node
   MUST be replaced with a Decoy.  When the entries fill all the leaves
   of the tree, no Decoy is added.

                                                   X
                                                   |
                           .-----------------------+-----------------------.
                           |                                               |
                           V                                               W
                           |                                               |
                 .---------+---------.                           .---------+---------.
                /                     \                         /                     \
               R                       S                       T                       U
               |                       |                       |                       |
           .---+---.               .---+---.               .---+---.               .---+---.
          /         \             /         \             /         \             /         \
         J           K           L           M           N           O           P           Q
        / \         / \         / \         / \         / \         / \         / \         / \
       /   \       /   \       /   \       /   \       /   \       /   \       /   \       /   \
      A     B     C     D     E     F     G     H     I     d     d     _     d     _     _     _

Node: 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Leaf: 0     1     2     3     4     5     6     7     8     9     10    11    12    13    14    15

                       Figure 4: Placing Decoys

   In Figure 4, the tree contains 9 entries.  Decoys (d) are placed as
   follows:

   1.  The rightmost entry of the tree is I.

   2.  Its copath consists of nodes 18, 21, 27, and 7 (_, O, U, and V).

   3.  For each node in this copath, the leftmost blank leaf of its
       subtree is replaced with a Decoy.  A blank copath node that is
       itself a leaf, such as 18, is replaced directly.

Maldant                   Expires 29 April 2027                 [Page 7]
Internet-Draft                   SMD-CWT                    October 2026

   4.  Consequently, nodes 18, 20, and 24 are replaced with Decoys.

4.3.  Computing the Merkle Root Hash

   The Issuer then computes the root hash of the Merkle tree as follows:

   1.  Each entry is encoded as a bstr-encoded-salted-merkle-entry, as
       defined in Figure 9.

   2.  The resulting bytes are hashed using the hash algorithm indicated
       by sd_alg in the protected header.

   3.  The hash of a parent node is the hash of the concatenation of the
       hashes of its two children, the hash of the left child coming
       first.

   This operation is denoted MTH (Merkle Tree Hash), similarly to the
   one described in Section 2.1.1 of [RFC9162].  Unlike in [RFC9162], no
   domain separation prefix is added to the leaves and the nodes: since
   the tree is balanced and its size is authenticated by the Issuer, all
   leaves are at the same depth.  The MTH of an interior node therefore
   cannot be used as the hash of a leaf, and second preimage resistance
   between leaves and nodes is not required.

4.3.1.  Inserting the Merkle Root Hash in the Payload

   The root hash is then inserted into the original payload in place of
   the redacted claims.  These claims are declared within a container,
   which is either a map or an array.  Since the container itself is
   annotated with the To Be Redacted Root Tag, it cannot contain regular
   redacted_claim_keys (simple value 59) or redacted array elements (tag
   60).

   Regardless of the type of the parent container, the root hash is
   represented as a redacted_root_hash: an array of two elements, the
   first of which is the logarithmic size of the Merkle tree producing
   the root hash, and the second of which is the root hash itself.

   redacted_root_hash = [
     uint,  ; base-2 logarithm of the number of leaves represented in this root hash
     bstr, ; root hash
   ]

                        Figure 5: Redacted Root Hash

   If the redaction occurs in a map, the redacted_root_hash is placed in
   the redacted_claim_hash claim.

Maldant                   Expires 29 April 2027                 [Page 8]
Internet-Draft                   SMD-CWT                    October 2026

   / redacted_claim_hash / simple(60) : [ uint, bstr ] / redacted_root_hash /

                       Figure 6: Redacted Claim Hash

   If the redaction occurs in an array, the root hash is placed in an
   redacted_element_hash element appended to the array, after the
   elements that are not redacted.

   "inspection_dates" : [
       1612498440, / item 1 not redacted /
       89([ uint, bstr ]) / root hash of item 0 and 2 /
   ],

                      Figure 7: Redacted Element Hash

4.4.  Disclosure

   Figure 8 shows the disclosure of the inspection_location claim from
   Figure 1.

   <<[
       [
           /salt/   h'e39612407e99a347d61442957b3dfdac',
           /value/  "us",
           /claim/  "country"
       ],
       [
           /salt/   h'4569990258b25a5267c17a3e3a225ec3',
           /value/  "ca",
           /claim/  "region"
       ],
       [
           /salt/   h'e27403129cd88bf8fee4193e65339a35',
       ]
   ]>>

                       Figure 8: SMD-CWT Disclosures

   In an SMD-CWT, a Disclosure is an array of all redacted elements of a
   given container (either a CBOR map or array).  Each of these elements
   has the structure described in Section 3.2 of [SD-CWT], except that
   they are not individually wrapped in a CBOR bstr (but the outer
   disclosure is).

   This Disclosure, along with all other Disclosures, MUST be placed in
   the sd_claims unprotected header parameter of the SMD-CWT, as defined
   in [SD-CWT].

Maldant                   Expires 29 April 2027                 [Page 9]
Internet-Draft                   SMD-CWT                    October 2026

   ; an array of bstr-encoded Salted Disclosed Claims
   ; in SMD-CWT
   salted-merkle-array = [ +bstr-encoded-salted-merkle-entry ]
   bstr-encoded-salted-merkle-entry = bstr .cbor salted-merkle-entries

   ; in SMD-KBT
   salted-array-proofs = [ +bstr-encoded-salted-proof ]
   bstr-encoded-salted-proof = bstr .cbor disclosure-proof

   ; where salted-claim, salted-element and decoy are already defined in {{SD-CWT}}
   salted-merkle-entry = salted-claim / salted-element / decoy

   salted-merkle-entries = [ +salted-merkle-entry ]

   ; one Merkle proof per presented leaf, ordered by increasing node index
   disclosure-proof = [ +merkle-proof ]

   merkle-proof = [
     redacted-entry,
     * bstr             ; hash of a copath node, from the leaf up to the root
   ]

   ; a presented entry prefixed with the node index of its leaf; Decoys are never presented
   redacted-entry = salted-merkle-claim / salted-merkle-element
   salted-merkle-claim = [
     uint,              ; node index of the leaf
     bstr .size 16,     ; 128-bit salt
     any,               ; Claim Value
     (int / text)       ; Claim Key
   ]
   salted-merkle-element = [
     uint,              ; node index of the leaf
     bstr .size 16,     ; 128-bit salt
     any                ; Claim Value
   ]

   ; repeated here
   salted-claim = [
     bstr .size 16,     ; 128-bit salt
     any,               ; Claim Value
     (int / text)       ; Claim Key
   ]
   salted-element = [
     bstr .size 16,     ; 128-bit salt
     any                ; Claim Value
   ]
   decoy = [
     bstr .size 16      ; 128-bit salt

Maldant                   Expires 29 April 2027                [Page 10]
Internet-Draft                   SMD-CWT                    October 2026

   ]

                 Figure 9: CDDL of Salted Disclosed Claims

   Figure 10 shows the SMD-CWT issued from Figure 2.  Each of the three
   containers tagged with the To Be Redacted Root Tag is replaced with a
   Redacted Root Hash, and its Disclosure is placed in sd_claims:

   / cose-sign1 / 18([  / issuer SMD-CWT /
     / CWT protected / << {
       / alg /    1  : -35, / ES384 /
       / kid /    4  : 'https://issuer.example/cose-key3',
       / typ /    16 : 294, / smd-cwt+sd-cwt (TBD1) /
       / sd_alg / 170 : -16  / SHA256 /
     } >>,
     / CWT unprotected / {
       / sd_claims / 17 : [ / these are all the disclosures /
           / top-level claims /
           <<[
               [
                   /salt/   h'34821e0250edb1b8aa1e7fcaba161dd5',
                   /value/  "ABCD-123456",
                   /claim/  "inspector_license_number"
               ],
               [
                   /salt/   h'96e374cd67609df517d855e6ad3892f5'
               ],
               [
                   /salt/   h'dab6a2fe5be976c64c0006d738fca0ef'
               ],
               [
                   /salt/   h'ae02b9b92e7ca06c3326b357118fcc57'
               ]
           ]>>,
           / inspection_dates /
           <<[
               [
                   /salt/   h'ad696c9e08b91319073b35c4df54715e',
                   /value/  1549560720   / inspected 7-Feb-2019 /
               ],
               [
                   /salt/   h'7ed13a094d0effbf257f5522fdb87446',
                   /value/  1612498440   / inspected 4-Feb-2021 /
               ],
               [
                   /salt/   h'd006ff82a4d84bcade7a008ad0fadb6e',
                   /value/  1674004740   / inspected 17-Jan-2023 /
               ],

Maldant                   Expires 29 April 2027                [Page 11]
Internet-Draft                   SMD-CWT                    October 2026

               [
                   /salt/   h'ff65d029bca807f1fcd7fc7a66223ae1'
               ],
               [
                   /salt/   h'c7ecad77d36b5b171573d2e32d650a1e'
               ]
           ]>>,
           / inspection_location /
           <<[
               [
                   /salt/   h'e39612407e99a347d61442957b3dfdac',
                   /value/  "us",
                   /claim/  "country"
               ],
               [
                   /salt/   h'4569990258b25a5267c17a3e3a225ec3',
                   /value/  "ca",
                   /claim/  "region"
               ],
               [
                   /salt/   h'e27403129cd88bf8fee4193e65339a35'
               ]
           ]>>
       ]
     },
     / CWT payload / << {
       / iss / 1   : "https://issuer.example",
       / sub / 2   : "https://holder.example",
       / exp / 4   : 1725330600,  /2024-09-03T02:30:00+00:00Z/
       / nbf / 5   : 1725243900,  /2024-09-02T02:25:00+00:00Z/
       / iat / 6   : 1725244200,  /2024-09-02T02:30:00+00:00Z/
       / cnf / 8   : {
         / cose key / 1 : {
           / kty /  1: 2,  / EC2   /
           / crv / -1: 1,  / P-256 /
           / x /   -2: h'8554eb275dcd6fbd1c7ac641aa2c90d9
                         2022fd0d3024b5af18c7cc61ad527a2d',
           / y /   -3: h'4dc7ae2c677e96d0cc82597655ce92d5
                         503f54293d87875d1e79ce4770194343'
         }
       },
       "most_recent_inspection_passed": true,
       "inspection_dates": [
           / redacted_element_hash of all inspection dates /
           89([3, h'a9e2b659695a7af97fcf25f8e833ffa2
                    0a4316fe29644715bdbd3804ac2bed99'])
       ],
       "inspection_location": {

Maldant                   Expires 29 April 2027                [Page 12]
Internet-Draft                   SMD-CWT                    October 2026

           "postal_code": "94188",
           / redacted_claim_hash of country and region /
           simple(60) : [2, h'02d992604bf0618156a8f5eef336f676
                           1db9af99edbc662e7c32850557a0ebd9']
       },
       / redacted_claim_hash of inspector_license_number /
       simple(60) : [3, h'3641ce21bec3c8c109da92b0be662719
                       b67cd8a99e99cd3b379c1ff466c0ec28']
     } >>,
     / CWT signature / h'dc15ca869bad13b9a827191d7d71a444
                         7ff213168f401982009a1c3629bce4a5
                         921642d9f15707541fdc7d9bad5d37b6
                         5d4d779b72273b9d1776a6675920a1a2
                         68272dc848858b9ccdfc45521bbb3247
                         316db1b829b63d63198af2b608826768'
   ])

               Figure 10: Issued SMD-CWT with all disclosures

4.5.  Content-Type

   An SMD-CWT MUST declare its content type by including the typ
   protected header parameter [RFC9596] with one of the following
   values:

   *  the unsigned integer Constrained Application Protocol (CoAP)
      [RFC7252] content-format value TBD1 (294 suggested); or

   *  the string content type value application/smd-cwt+sd-cwt.

5.  Presentation

   A Holder can selectively present some of the previously redacted
   claims in an SMD-KBT.  An SMD-KBT has the same structure as an SD-
   KBT.  The only difference is that, rather than simply omitting the
   Disclosures it does not wish to reveal, the Holder transforms each
   Disclosure introduced by this document from a simple enumeration of
   values into a Disclosure Proof: an array containing one Merkle proof
   per presented leaf.

   The Merkle proofs of a Disclosure Proof are not independent of each
   other.  The hash of a copath node is not included in a Merkle proof
   when its subtree contains a presented leaf, since the Verifier
   recomputes it, or when it is already included in the Merkle proof of
   a previous leaf.

   For a given Disclosure, the Holder proceeds as follows:

Maldant                   Expires 29 April 2027                [Page 13]
Internet-Draft                   SMD-CWT                    October 2026

   1.  Iterate over the non-Decoy entries and select those to be
       presented.  In the example of Figure 11, leaves A to E are
       iterated over, and only A, D, and E are presented.

   2.  Initialize a visited set with the node indexes of the selected
       leaves and of all their ancestors.  In the example of Figure 11,
       the visited set contains nodes 0, 6, and 8 (A, D, and E) and
       nodes 1, 3, 5, 7, 9, and 11 (J, R, K, V, L, and S).

   3.  For each selected leaf, from left to right, build its Merkle
       proof as an array:

       1.  Build a Redacted Entry by prefixing the SMD-CWT entry with
           the node index of the leaf, and place it as the first element
           of the Merkle proof.

       2.  Walk the copath of that leaf, from the leaf up to the root.
           For each node of the copath:

           1.  If this node is in the visited set, skip it.

           2.  Otherwise, append the hash of that node to the Merkle
               proof and add the node to the visited set.  If that node
               is a leaf, its hash is the hash of its entry, computed as
               described in Section 4.3.  Otherwise, its hash is the MTH
               of the subtree rooted at that node.

   4.  The Disclosure Proof is the array of the Merkle proofs, ordered
       by increasing node index of their leaf.

                              V
                              |
                    .---------+---------.
                   /                     \
                  R                       S
                  |                       |
              .---+---.               .---+---.
             /         \             /         \
            J           K           L           M
           / \         / \         / \         / \
          /   \       /   \       /   \       /   \
         A    (B)   (C)    D     E    d1     d2    _

   Node: 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14

   Leaf: 0     1     2     3     4     5     6     7

                  Figure 11: Merkle Tree of a Presentation

Maldant                   Expires 29 April 2027                [Page 14]
Internet-Draft                   SMD-CWT                    October 2026

   In the following examples, hash<<X>> denotes the hash of the entry X
   when X is a leaf, and the MTH of the subtree rooted at X otherwise.

   The copath of A consists of nodes 2 (B), 5 (K), and 11 (S).  B is not
   visited: its hash is appended.  K and S are visited: they are
   skipped.  The Merkle proof for A is therefore:

   [
     [0, h'4e2f040d5bb57daf86698066be470c24', "A"],
     hash<<B>>,
   ]

                        Figure 12: Merkle Proof of A

   The copath of D consists of nodes 4 (C), 1 (J), and 11 (S).  C is not
   visited: its hash is appended.  J and S are visited: they are
   skipped.  The Merkle proof for D is therefore:

   [
     [6, h'add7fe2b052af5faf0ec67f57eb1454f', "D"],
     hash<<C>>,
   ]

                        Figure 13: Merkle Proof of D

   The copath of E consists of nodes 10 (d1), 13 (M), and 3 (R). d1 and
   M are not visited: their hashes are appended.  R is visited: it is
   skipped.  The Merkle proof for E is therefore:

   [
     [8, h'6e0e0494c6aa9f9072c3410304aab730', "E"],
     hash<<d1>>,
     hash<<M>>,
   ]

                        Figure 14: Merkle Proof of E

   The resulting Disclosure Proof is shown in Figure 15.  It contains 4
   hashes.  The hashes of J, K, R, L, S, and V are recomputed by the
   Verifier.

   [
     [ [0, h'4e2f040d5bb57daf86698066be470c24', "A"], hash<<B>> ],             / "A" /
     [ [6, h'add7fe2b052af5faf0ec67f57eb1454f', "D"], hash<<C>> ],             / "D" /
     [ [8, h'6e0e0494c6aa9f9072c3410304aab730', "E"], hash<<d1>>, hash<<M>> ]  / "E" /
   ]

                        Figure 15: Disclosure Proof

Maldant                   Expires 29 April 2027                [Page 15]
Internet-Draft                   SMD-CWT                    October 2026

   If the Holder presents all the non-Decoy entries A to E of Figure 11
   instead, every copath node of A, B, C, and D is visited: their Merkle
   proofs each contain only their Redacted Entry.  The Merkle proof of E
   is unchanged and contains hash<<d1>> and hash<<M>>.  The resulting
   Disclosure Proof contains 2 hashes.

   If the Holder presents only A and B, the Merkle proof of A contains
   hash<<K>> and hash<<S>>, which are then visited, so the Merkle proof
   of B contains no hash.

6.  Verification

   An SMD-CWT Verifier MUST perform the same verification as an SD-CWT
   Verifier.  This section only describes how to validate a Disclosure
   Proof against the redacted_root_hash of the corresponding container.

   To validate an SMD-KBT, repeat this verification for all the
   disclosures presented.  Then also perform the validation described in
   Section 9 of [SD-CWT] since they all should pass as well.

   In this section, n is the size encoded in the redacted_root_hash (the
   first element of the array); the Merkle tree therefore has 2^n
   leaves, its node indexes range from 0 to 2^ (n+1) - 2, and its root
   has node index 2^n - 1.

   The Verifier proceeds as follows:

   1.  Verify that the Disclosure Proof contains at least one and at
       most 2^n Merkle proofs.

   2.  For each Merkle proof:

       1.  Verify that it contains at most n + 1 elements.

       2.  Verify that its first element is a Redacted Entry, and that
           the node index of this Redacted Entry is the node index of a
           leaf, i.e., an even number less than or equal to 2^ (n+1) -
           2.

       3.  Verify that this Redacted Entry matches the type of the
           container: a salted-merkle-claim if the container is a map,
           or a salted-merkle-element if it is an array, as defined in
           Figure 9.  In particular, a Redacted Entry of a Decoy, which
           only contains a salt, is rejected.

   3.  Verify that the node indexes of the Redacted Entries are sorted
       in increasing order.

Maldant                   Expires 29 April 2027                [Page 16]
Internet-Draft                   SMD-CWT                    October 2026

   4.  Initialize a visited set with the node indexes of the presented
       leaves and of all their ancestors.  Also maintain a table
       associating node indexes with hashes, initially empty.

   5.  For each Merkle proof:

       1.  Remove the node index from the Redacted Entry.  The remaining
           array is an SMD-CWT entry: compute its hash as described in
           Section 4.3 and record it for the leaf in the table.

       2.  Walk the copath of the leaf, from the leaf up to the root.
           For each node of the copath:

           1.  If this node is in the visited set, skip it.

           2.  Otherwise, take the next hash of the Merkle proof, record
               it for that node in the table, and add the node to the
               visited set.  If the Merkle proof has no hash left, the
               validation fails.

       3.  Verify that all the hashes of the Merkle proof have been
           consumed.  If not, the validation fails.

   6.  Compute the hash of the root by walking down the tree from the
       root.  For each node reached:

       1.  If the table records a hash for this node, this is its hash,
           and its subtree is not walked.

       2.  Otherwise, if this node is a leaf, the validation fails.

       3.  Otherwise, walk its left child and then its right child.  Its
           hash is the hash of the concatenation of their hashes, the
           hash of the left child coming first.

   7.  Verify that the hash of the root is equal to the root hash in the
       redacted_root_hash.

   8.  If any of these verifications fails, the validation of the whole
       Disclosure Proof fails.

   Applied to the Disclosure Proof of Figure 15, the visited set
   initially contains nodes 0, 1, 3, 5, 6, 7, 8, 9, and 11.  The
   Verifier then:

   1.  Processes the Merkle proof of A: it records hash<<A>> for node 0
       and hash<<B>> for node 2.  Nodes 5 and 11 are visited.

Maldant                   Expires 29 April 2027                [Page 17]
Internet-Draft                   SMD-CWT                    October 2026

   2.  Processes the Merkle proof of D: it records hash<<D>> for node 6
       and hash<<C>> for node 4.  Nodes 1 and 11 are visited.

   3.  Processes the Merkle proof of E: it records hash<<E>> for node 8,
       hash<<d1>> for node 10, and hash<<M>> for node 13.  Node 3 is
       visited.

   4.  Computes the hash of the root.  The visited set now contains
       nodes 0 to 11 and 13, and the table associates nodes with hashes
       [(0, A), (2, B), (4, C), (6, D), (8, E), (10, d1), (13, M)].  The
       root V (node 7) is not in the table, so the Verifier walks down
       to R (node 3) and S (node 11), which are not in the table either.
       Under R, J (node 1) and K (node 5) are computed from nodes 0 and
       2, and 4 and 6.  Under S, L (node 9) is computed from nodes 8 and
       10, and M (node 13) is in the table.  R is then computed from J
       and K, S from L and M, and V from R and S.

   5.  Verifies that hash<<V>> is equal to the root hash in the
       redacted_root_hash.

7.  Benefits over SD-CWT

7.1.  Smaller Tokens

   In SD-CWT, the payload contains the hash of every redacted entry,
   disclosed or not: a container with e redacted entries costs 34 * e
   bytes in every presentation (assuming sd_alg is SHA-256).

   The size of a presentation therefore grows linearly with e in SD-CWT,
   but only logarithmically in SMD-CWT.  For instance, the Disclosure
   Proof of Figure 15 contains 4 hashes in addition to the root hash,
   i.e., 34 * 5 = 170 bytes, whereas an SD-CWT with the same 5 entries
   and 2 Decoys contains 34 * 7 = 238 bytes of hashes.

7.2.  Privacy

   In SD-CWT, the payload contains one hash per redacted entry, so a
   Verifier learns the number of redacted entries of each container Also
   given presentation of SD-KBT are linkable, a Verifier can witness an
   array of redacted elements grow or shrink which degrades privacy of
   the Holder.  Decoys can be used to mitigate that, but they are
   expensive in terms of space wasted.

   In SMD-CWT, the Verifier only learns the logarithmic size of the
   tree.  The Issuer can choose a larger n to hide this number further,
   at the cost of at most one hash per additional level (see
   Section 7.3).

Maldant                   Expires 29 April 2027                [Page 18]
Internet-Draft                   SMD-CWT                    October 2026

7.3.  Free Decoys

   In SD-CWT, each Decoy adds one hash, i.e., 34 bytes, to the presented
   token.

   In SMD-CWT, the presented token contains only the root hash and the
   Merkle proofs of the disclosed claims.  The size of these proofs
   depends on the height of the tree, not on the number of its leaves.
   Decoys can therefore be added at no cost up to the next power of two.
   Beyond that, doubling the number of leaves adds one level to the
   tree, which costs at most one additional hash, i.e., 34 bytes: the
   subtree rooted at the new copath node contains no presented leaf, and
   its hash is included at most once in the Disclosure Proof (see
   Section 5).

7.4.  Verification Time

   TODO: The sparser the presentation, the faster the verification;
   however, a full presentation takes twice as long to verify.

8.  Privacy Considerations

8.1.  Leakage of Claim Order

9.  Security Considerations

   TODO Security

10.  IANA Considerations

10.1.  CBOR Tags

   IANA is requested to register the following tag in the "CBOR Tags"
   registry (https://www.iana.org/assignments/cbor-tags/cbor-
   tags.xhtml#tags):

10.1.1.  To Be Redacted Root Tag

   This tag identifies an array or map containing elements to be
   redacted.  The value of this tag is an array of two elements: the
   first is the base-2 logarithm of the number of leaves of the Merkle
   tree, i.e., the maximum number of hashes in a Merkle proof, and the
   second is the wrapped array or map.

   *  Tag: TBD2 (suggested 59)

   *  Data Item: (array or map)

Maldant                   Expires 29 April 2027                [Page 19]
Internet-Draft                   SMD-CWT                    October 2026

   *  Semantics: An array or map containing elements to be redacted with
      a Merkle proof, each tagged with the To Be Redacted Tag defined in
      Section 17.3.1 of [SD-CWT].

   *  Specification Document (s): Section 4.1 of this specification

10.2.  Media Types

   IANA is requested to register the following media types in the "Media
   Types" registry (https://www.iana.org/assignments/media-types/media-
   types.xhtml#application):

10.2.1.  application/smd-cwt+sd-cwt

   The following completed registration template is provided:

   *  Type name: application

   *  Subtype name: smd-cwt

   *  Required parameters: n/a

   *  Optional parameters: n/a

   *  Encoding considerations: binary

   *  Security considerations: Section 9 of this specification and
      [RFC8392]

   *  Interoperability considerations: n/a

   *  Published specification: Section 4 of this specification

   *  Applications that use this media type: TBD

   *  Fragment identifier considerations: n/a

   *  Additional information:

      -  Magic number (s): n/a

      -  File extension (s): n/a

      -  Macintosh file type code (s): n/a

   *  Person & email address to contact for further information: SPICE
      WG mailing list (spice@ietf.org) or IETF Security Area
      (saag@ietf.org)

Maldant                   Expires 29 April 2027                [Page 20]
Internet-Draft                   SMD-CWT                    October 2026

   *  Intended usage: COMMON

   *  Restrictions on usage: none

   *  Author: See Author's Addresses section

   *  Change controller: IETF

   *  Provisional registration?  No

10.2.2.  application/smd-kbt+sd-kbt

   The following completed registration template is provided:

   *  Type name: application

   *  Subtype name: smd-kbt

   *  Required parameters: n/a

   *  Optional parameters: n/a

   *  Encoding considerations: binary

   *  Security considerations: Section 9 of this specification and
      [RFC8392]

   *  Interoperability considerations: n/a

   *  Published specification: Section 5 of this specification

   *  Applications that use this media type: TBD

   *  Fragment identifier considerations: n/a

   *  Additional information:

      -  Magic number (s): n/a

      -  File extension (s): n/a

      -  Macintosh file type code (s): n/a

   *  Person & email address to contact for further information: SPICE
      WG mailing list (spice@ietf.org) or IETF Security Area
      (saag@ietf.org)

   *  Intended usage: COMMON

Maldant                   Expires 29 April 2027                [Page 21]
Internet-Draft                   SMD-CWT                    October 2026

   *  Restrictions on usage: none

   *  Author: See Author's Addresses section

   *  Change controller: IETF

   *  Provisional registration?  No

11.  References

11.1.  Normative References

   [I-D.ietf-cbor-edn-literals]
              Bormann, C., "Concise Diagnostic Notation (CDN)", Work in
              Progress, Internet-Draft, draft-ietf-cbor-edn-literals-28,
              29 September 2026, <https://datatracker.ietf.org/doc/html/
              draft-ietf-cbor-edn-literals-28>.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/rfc/rfc2119>.

   [RFC7519]  Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token
              (JWT)", RFC 7519, DOI 10.17487/RFC7519, May 2015,
              <https://www.rfc-editor.org/rfc/rfc7519>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/rfc/rfc8174>.

   [RFC8392]  Jones, M., Wahlstroem, E., Erdtman, S., and H. Tschofenig,
              "CBOR Web Token (CWT)", RFC 8392, DOI 10.17487/RFC8392,
              May 2018, <https://www.rfc-editor.org/rfc/rfc8392>.

   [RFC8610]  Birkholz, H., Vigano, C., and C. Bormann, "Concise Data
              Definition Language (CDDL): A Notational Convention to
              Express Concise Binary Object Representation (CBOR) and
              JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610,
              June 2019, <https://www.rfc-editor.org/rfc/rfc8610>.

   [RFC9052]  Schaad, J., "CBOR Object Signing and Encryption (COSE):
              Structures and Process", STD 96, RFC 9052,
              DOI 10.17487/RFC9052, August 2022,
              <https://www.rfc-editor.org/rfc/rfc9052>.

Maldant                   Expires 29 April 2027                [Page 22]
Internet-Draft                   SMD-CWT                    October 2026

   [RFC9053]  Schaad, J., "CBOR Object Signing and Encryption (COSE):
              Initial Algorithms", RFC 9053, DOI 10.17487/RFC9053,
              August 2022, <https://www.rfc-editor.org/rfc/rfc9053>.

   [RFC9162]  Laurie, B., Messeri, E., and R. Stradling, "Certificate
              Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162,
              December 2021, <https://www.rfc-editor.org/rfc/rfc9162>.

   [RFC9420]  Barnes, R., Beurdouche, B., Robert, R., Millican, J.,
              Omara, E., and K. Cohn-Gordon, "The Messaging Layer
              Security (MLS) Protocol", RFC 9420, DOI 10.17487/RFC9420,
              July 2023, <https://www.rfc-editor.org/rfc/rfc9420>.

   [RFC9596]  Jones, M.B. and O. Steele, "CBOR Object Signing and
              Encryption (COSE) "typ" (type) Header Parameter",
              RFC 9596, DOI 10.17487/RFC9596, June 2024,
              <https://www.rfc-editor.org/rfc/rfc9596>.

   [SD-CWT]   Prorock, M., Steele, O., Birkholz, H., and R. Mahy,
              "Selective Disclosure CBOR Web Tokens (SD-CWT)", Work in
              Progress, Internet-Draft, draft-ietf-spice-sd-cwt-08, 1
              June 2026, <https://datatracker.ietf.org/doc/html/draft-
              ietf-spice-sd-cwt-08>.

11.2.  Informative References

   [RFC7252]  Shelby, Z., Hartke, K., and C. Bormann, "The Constrained
              Application Protocol (CoAP)", RFC 7252,
              DOI 10.17487/RFC7252, June 2014,
              <https://www.rfc-editor.org/rfc/rfc7252>.

Appendix A.  Complete CDDL Schema

   ; in SMD-CWT
   salted-merkle-array = [ +bstr-encoded-salted-merkle-entry ]
   bstr-encoded-salted-merkle-entry = bstr .cbor salted-merkle-entries

   ; in SMD-KBT
   salted-array-proofs = [ +bstr-encoded-salted-proof ]
   bstr-encoded-salted-proof = bstr .cbor disclosure-proof

   ; where salted-claim, salted-element and decoy are already defined in {{SD-CWT}}
   salted-merkle-entry = salted-claim / salted-element / decoy

   salted-merkle-entries = [ +salted-merkle-entry ]

   ; one Merkle proof per presented leaf, ordered by increasing node index
   disclosure-proof = [ +merkle-proof ]

Maldant                   Expires 29 April 2027                [Page 23]
Internet-Draft                   SMD-CWT                    October 2026

   merkle-proof = [
     redacted-entry,
     * bstr             ; hash of a copath node, from the leaf up to the root
   ]

   ; a presented entry prefixed with the node index of its leaf; Decoys are never presented
   redacted-entry = salted-merkle-claim / salted-merkle-element
   salted-merkle-claim = [
     uint,              ; node index of the leaf
     bstr .size 16,     ; 128-bit salt
     any,               ; Claim Value
     (int / text)       ; Claim Key
   ]
   salted-merkle-element = [
     uint,              ; node index of the leaf
     bstr .size 16,     ; 128-bit salt
     any                ; Claim Value
   ]

   ; repeated here
   salted-claim = [
     bstr .size 16,     ; 128-bit salt
     any,               ; Claim Value
     (int / text)       ; Claim Key
   ]
   salted-element = [
     bstr .size 16,     ; 128-bit salt
     any                ; Claim Value
   ]
   decoy = [
     bstr .size 16      ; 128-bit salt
   ]

   ; redacted_claims_root is used as a map label. The corresponding value is
   ; a Redacted Claim Root Hash.
   ; TODO: any Unassigned value in https://www.iana.org/assignments/cbor-simple-values#simple
   redacted_claims_hash = #7.60  ; CBOR simple value 60

   redacted_root_hash = [
     uint  ; logarithm(2) of the number of leaves represented in this root hash
     bstr, ; root hash
   ]

   ; CBOR tag for wrapping the Merkle Root Hash of all the redacted elements in an array.
   ; TODO: any Unassigned in https://www.iana.org/assignments/cbor-tags#tags
   MERKLE_REDACTED_ELEMENT_TAGNUM = 89

   ; redacted_elements_root is used in CDDL payloads that contain

Maldant                   Expires 29 April 2027                [Page 24]
Internet-Draft                   SMD-CWT                    October 2026

   ; array elements that are redacted.
   redacted_element_hash = #6.<MERKLE_REDACTED_ELEMENT_TAGNUM>( redacted_root_hash )

             Figure 16: A complete CDDL description of SMD-CWT

Acknowledgments

   TODO acknowledge.

Author's Address

   Beltram Maldant
   SimpleLogin
   Email: beltram.ietf@pm.me

Maldant                   Expires 29 April 2027                [Page 25]