本规范描述了一种数据完整性加密套件,用于生成使用BBS签名方案的数字签名。 该签名套件利用BBS签名提供选择性披露和不可链接的派生证明。

工作组正在积极寻求对本规范的实施反馈。为了退出候选推荐阶段,工作组要求每个功能(包括强制性和可选功能)至少有两个独立的实现。有关一致性测试过程的详细信息,请参阅 实施报告

介绍

本规范定义了一种加密套件,用于创建、验证和派生使用 BBS 签名方案的证明,以符合数据完整性 [[VC-DATA-INTEGRITY]] 规范。 BBS 签名方案直接提供选择性披露和不可链接的证明。它在 发行方、持有方、验证方 模型中提供了四个高级功能。具体来说,发行方使用 BBS 的 `Sign` 函数创建一种被称为“BBS 签名”的加密值,用于签署原始凭证。持有方在接收到使用 BBS 签名的凭证后,使用 BBS 的 `Verify` 函数验证该凭证。

持有方随后从接收到的凭证中选择性披露信息,并使用 BBS 的 `ProofGen` 函数生成一种被称为“BBS 证明”的加密值,用于为该“派生凭证”创建证明。加密的“BBS 证明”值无法链接到原始的“BBS 签名”,持有方可以为其他“派生凭证”生成不同的、不可链接的“BBS 证明”,即使这些凭证包含完全相同的信息。 最后,验证方使用 BBS 的 `ProofVerify` 函数验证从持有方接收到的派生凭证。

将 BBS 签名方案应用于可验证凭证涉及本文件中指定的处理过程。 通常,该套件使用 RDF 数据集规范化算法 [[RDF-CANON]] 将输入文档转换为其规范形式。发行方随后使用选择性披露原语将规范形式分为强制性和非强制性声明。这些声明与其他信息分开处理,作为 BBS `Sign` 函数的输入以及适当的密钥材料。此输出用于生成安全的凭证。持有方在接收到凭证后,使用一组选择性披露功能和 BBS 的 `Verify` 函数来验证凭证的有效性。

同样,在接收到 BBS 签名的凭证后,持有方使用 RDF 数据集规范化算法 [[RDF-CANON]] 将输入文档转换为其规范形式,然后应用选择性披露原语将规范形式分为强制性和选择性披露的声明,这些声明经过适当处理后作为 BBS `ProofGen` 函数的输入。经过适当处理后,该函数的输出成为发送给验证方的签名选择性披露凭证。使用规范化和选择性披露原语,验证方随后可以使用 BBS 的 `verifyProof` 函数验证凭证。

术语

本文件中使用的术语在 [[[[VC-DATA-INTEGRITY]]]] 规范的 术语部分中定义。

符合性证明是符合本规范中的规范性声明的任何数据模型的具体表达形式。具体来说,本文件第 节中的所有相关规范性声明必须被强制执行。

符合性处理器是任何以软件和/或硬件实现的算法,用于生成或消费 符合性证明。符合性处理器在消费不符合规范的文档时必须产生错误。

本文件包含 JSON 和 JSON-LD 数据的示例。这些示例中有些是无效的 JSON,因为它们包含诸如内联注释(`//`)解释某些部分以及省略号(`...`)表示与示例无关的信息的省略等特性。如果实现者希望将这些示例视为有效的 JSON 或 JSON-LD,则需要移除这些部分。

数据模型

以下部分概述了本规范中用于验证方法数据完整性证明格式的数据模型。

验证方法

这些验证方法用于验证使用符合 [[CFRG-BBS-SIGNATURE]] 的 BLS12-381 加密密钥材料生成的数据完整性证明 [[VC-DATA-INTEGRITY]]。本节提供了这些密钥类型的编码格式。在处理数字签名时,可以使用无损的加密密钥转换过程以生成等效的加密密钥材料。

多密钥

多密钥格式,定义于 [[[CID]]],用于表示本规范中定义的加密套件的公钥。

`publicKeyMultibase` 属性表示 BLS12-381 G2 组中 381 位公钥的多基编码多密钥表达。

验证方法的 `publicKeyMultibase` 值必须以 base-58-btc 前缀 (`z`) 开头,如 [[[CID]]] 的 多基部分中定义。接下来是多基编码的 BLS12-381 381 位公钥值,如 [[[CID]]] 的 多密钥部分中定义。不允许使用任何其他编码。

开发者需注意不要意外发布私钥的表示形式。如果在 `publicKeyMultibase` 值中使用了 `0xeb01` 以外的多编解码值,本规范的实现将引发错误。

{
  "id": "https://example.com/issuer/123#key-0",
  "type": "Multikey",
  "controller": "https://example.com/issuer/123",
  "publicKeyMultibase": "zUC7EK3ZakmukHhuncwkbySmomv3FmrkmS36E4Ks5rsb6VQSRpoCrx6
  Hb8e2Nk6UvJFSdyw9NK1scFXJp21gNNYFjVWNgaqyGnkyhtagagCpQb5B7tagJu3HDbjQ8h
  5ypoHjwBb"
}
      
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1"
  ],
  "id": "https://example.com/issuer/123",
  "verificationMethod": [{
    "id": "https://example.com/issuer/123#key-1",
    "type": "Multikey",
    "controller": "https://example.com/issuer/123",
    "publicKeyMultibase": "zUC7EK3ZakmukHhuncwkbySmomv3FmrkmS36E4Ks5rsb6VQSRpoCr
    x6Hb8e2Nk6UvJFSdyw9NK1scFXJp21gNNYFjVWNgaqyGnkyhtagagCpQb5B7tagJu3HDbjQ8h
    5ypoHjwBb"
  }]
}
      

证明表示

数据完整性证明

证明包含 [[VC-DATA-INTEGRITY]] 的 证明部分中指定的属性,并具有以下限制。

证明的 `verificationMethod` 属性必须是一个 URL。解析 `verificationMethod` 必须返回一个包含 `type` 属性且值为 `Multikey` 的对象。

证明的 `type` 属性必须为 `DataIntegrityProof`。

证明的 `cryptosuite` 属性必须为 `bbs-2023`。

证明的 `proofValue` 属性的值必须是根据 [[CFRG-BBS-SIGNATURE]] 生成的 BBS 签名或 BBS 证明,并按照 部分中的程序进行序列化和编码。

算法

以下算法描述了如何使用 BBS 签名方案 [[CFRG-BBS-SIGNATURE]] 处理可验证凭证。在使用 BBS 签名方案时,应使用 SHA-256 变体。

实现应尽早获取并缓存验证方法信息,以便在添加或验证证明时使用。本节中传递给函数的参数使用来自验证方法的信息(例如公钥大小)来确定函数参数(例如加密哈希算法)。

当使用 RDF 数据集规范化算法 [[RDF-CANON]] 时,该算法的实现将默认检测 数据集污染,并在检测到时中止处理。

初始化加密套件

此算法用于配置加密套件,以供 [[[VC-DATA-INTEGRITY]]] 中的 添加证明验证证明函数使用。该算法接受一个选项对象 ([=map=] |options|)作为输入,并返回一个[=数据完整性加密套件实例|加密套件实例=]([=struct=] |cryptosuite|)。

  1. 将 |cryptosuite| 初始化为空的 [=struct=]。
  2. 如果 |options|.|type| 不等于 `DataIntegrityProof`,则返回 |cryptosuite|。
  3. 如果 |options|.|cryptosuite| 为 `bbs-2023`,则:
    1. 将 |cryptosuite|.|createProof| 设置为第 [[[#create-base-proof-bbs-2023]]] 节中的算法。
    2. 将 |cryptosuite|.|verifyProof| 设置为第 [[[#verify-derived-proof-bbs-2023]]] 节中的算法。
  4. 返回 |cryptosuite|。

选择性披露函数

createShuffledIdLabelMapFunction

以下算法创建一个标签映射工厂函数,该函数使用 HMAC 对规范化的空白节点标识符进行混淆。所需输入是一个 HMAC(之前已使用密钥初始化),|HMAC|。输出是一个函数 labelMapFactoryFunction

  1. 创建一个函数 |labelMapFactoryFunction|,该函数有一个必需的输入(规范化节点标识符映射 |canonicalIdMap|),并返回一个空白节点标识符映射 bnodeIdMap 作为输出。将函数的实现设置为:
    1. 生成一个新的空白节点标识符映射 bnodeIdMap
    2. 对于 |canonicalIdMap| 中的每个映射条目 entry
      1. entry 中值的规范化标识符执行 HMAC 操作,得到 HMAC 摘要 digest
      2. 生成一个新的字符串值 b64urlDigest,并将其初始化为 "u",然后附加 digest 值的 base64url-no-pad 编码版本。
      3. 使用 entry 的键和 b64urlDigest 作为值,向 bnodeIdMap 添加一个新条目 |newEntry|。
    3. 从 `bnodeIdMap` 中派生混淆映射,具体如下:
      1. 将 `hmacIds` 设置为 `bnodeIdMap` 中值的排序数组,将 `bnodeKeys` 设置为 `bnodeIdMap` 中键的有序数组。
      2. 对于 `bnodeKeys` 中的每个键,用该键在 `hmacIds` 数组中的索引位置(前缀为 "b")替换 `bnodeIdMap` 中该键的值,即: `bnodeIdMap.set(bkey, 'b' + hmacIds.indexOf(bnodeIdMap.get(bkey)))`。
    4. 返回 bnodeIdMap
  2. 返回 |labelMapFactoryFunction|。

需要注意的是,上述算法中的步骤 1.2 与 [[DI-ECDSA]] 的 第 3.3.4 节 `createHmacIdLabelMapFunction` 中的步骤 1.2 相同,因此开发者在实现两者时可能可以重用代码或调用该函数。

bbs-2023 函数

serializeBaseProofValue

以下算法序列化基础证明值,包括 BBS 签名、HMAC 密钥和强制性指针。 所需输入包括基础签名 |bbsSignature|、|bbsHeader|、|publicKey|、HMAC 密钥 |hmacKey|、一个数组 |mandatoryPointers|、|featureOption|,以及根据 |featureOption| 的值可能需要的 |signer_nym_entropy| 值。 输出是一个单一的 基础证明 字符串值。

  1. 根据 |featureOption| 的值,设置 |proofValue|,具体如下。
  2. 如果 |featureOption| 等于 `"baseline"`:
    1. 初始化一个字节数组 |proofValue|,以 BBS 基础证明头字节 `0xd9`、`0x5d` 和 `0x02` 开头。
    2. 将 |components| 初始化为一个包含以下五个元素的数组:|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey| 和 |mandatoryPointers|。
  3. 如果 |featureOption| 等于 `"anonymous_holder_binding"`:
    1. 初始化一个字节数组 |proofValue|,以 BBS 基础证明头字节 `0xd9`、`0x5d` 和 `0x04` 开头。
    2. 将 |components| 初始化为一个包含以下六个元素的数组:|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey| 和 |mandatoryPointers|。
  4. 如果 |featureOption| 等于 `"pseudonym"`:
    1. 初始化一个字节数组 |proofValue|,以 BBS 基础证明头字节 `0xd9`、`0x5d` 和 `0x06` 开头。
    2. 将 |components| 初始化为一个包含以下六个元素的数组:|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey|、|mandatoryPointers| 和 |signer_nym_entropy|。
  5. 如果 |featureOption| 等于 `"holder_binding_pseudonym"`:
    1. 初始化一个字节数组 |proofValue|,以 BBS 基础证明头字节 `0xd9`、`0x5d` 和 `0x08` 开头。
    2. 将 |components| 初始化为一个包含以下六个元素的数组:|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey|、|mandatoryPointers| 和 |signer_nym_entropy|。
  6. 根据 [[RFC8949]] 对 |components| 进行 CBOR 编码,其中 CBOR 标记不得用于任何 |components|。将生成的编码值附加到 |proofValue|。
  7. 将 |baseProof| 初始化为一个字符串,该字符串是 |proofValue| 的 multibase-base64url-no-pad 编码值。也就是说,返回一个以 "`u`" 开头并以 |proofValue| 的 base64url-no-pad 编码值结尾的字符串。
  8. 返回 |baseProof| 作为 基础证明

解析基础证明值

以下算法解析 `bbs-2023` 选择性披露基础证明值的组成部分。所需输入为一个证明值(|proofValue|)。输出为一个包含六个或七个元素的单一对象,使用以下名称:"bbsSignature"、"bbsHeader"、"publicKey"、"hmacKey"、"mandatoryPointers"、"featureOption",以及可能的可选特性参数 "signer_nym_entropy"。

  1. 如果 `proofValue` 字符串未以 u (U+0075 LATIN SMALL LETTER U) 开头,表明它不是 `multibase-base64url-no-pad-encoded` 值,则必须引发错误,并应传递错误类型 PROOF_VERIFICATION_ERROR
  2. 将 |decodedProofValue| 初始化为对 `proofValue` 中前导 `u` 后的子字符串进行 base64url-no-pad 解码的结果。
  3. 检查 BBS 基础证明是否以允许的头部值开头,并根据以下规则设置 |featureOption| 变量:
    1. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x02` 开头,则将 |featureOption| 设置为 `"baseline"`。
    2. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x04` 开头,则将 |featureOption| 设置为 `"anonymous_holder_binding"`。
    3. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x06` 开头,则将 |featureOption| 设置为 `"pseudonym"`。
    4. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x08` 开头,则将 |featureOption| 设置为 `"holder_binding_pseudonym"`。
    5. 如果 |decodedProofValue| 以任何其他三字节序列开头,则必须引发错误,并应传递错误类型 PROOF_VERIFICATION_ERROR
  4. 将 `components` 初始化为对三字节 BBS 基础证明头部后面的字节进行 CBOR 解码的结果数组。
  5. 根据 |featureOption| 的值,基于 |components| 返回一个对象,如下所示:
    1. 如果 |featureOption| 等于 `"baseline"`,则根据 |components| 设置对象的属性名称为 "bbsSignature"、"bbsHeader"、"publicKey"、"hmacKey" 和 "mandatoryPointers",并添加 |featureOption| 作为属性。
    2. 如果 |featureOption| 等于 `"anonymous_holder_binding"`,则根据 |components| 设置对象的属性名称为 "bbsSignature"、"bbsHeader"、"publicKey"、"hmacKey" 和 "mandatoryPointers",并添加 |featureOption| 作为属性。
    3. 如果 |featureOption| 等于 `"pseudonym"`,则根据 |components| 设置对象的属性名称为 "bbsSignature"、"bbsHeader"、"publicKey"、"hmacKey"、"mandatoryPointers" 和 "signer_nym_entropy",并添加 |featureOption| 作为属性。
    4. 如果 |featureOption| 等于 `"holder_binding_pseudonym"`,则根据 |components| 设置对象的属性名称为 "bbsSignature"、"bbsHeader"、"publicKey"、"hmacKey"、"mandatoryPointers" 和 "signer_nym_entropy",并添加 |featureOption| 作为属性。

创建披露数据

以下算法用于创建生成派生证明所需的数据。输入包括一个 JSON-LD 文档(|document|)、一个 BBS 基础证明(|proof|)、用于选择性披露声明的 JSON 指针数组(|selectivePointers|)、一个可选的 BBS |presentationHeader|(字节数组,默认为空字节数组)、一个 |featureOption| 指示器,以及 |featureOption| 所需的其他输入(参见 添加派生证明),以及任何自定义 JSON-LD API 选项(如文档加载器)。输出是一个单一对象,披露数据,包含以下字段:|bbsProof|、|labelMap|、|mandatoryIndexes|、|selectiveIndexes|、|presentationHeader|、|revealDocument|,以及(如果计算)|pseudonym|。

  1. 将 |bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey| 和 |mandatoryPointers| 初始化为调用第 节中的算法时返回的对象中相关属性的值,传递 `proof` 中的 `proofValue`。
  2. 使用 |hmacKey| 初始化一个 HMAC API,|hmac|。HMAC 使用与签名算法相同的哈希算法,即 SHA-256。
  3. 将 |labelMapFactoryFunction| 初始化为调用第 节中的算法的结果,传递 |hmac| 作为 |HMAC|。
  4. 将 |combinedPointers| 初始化为 |mandatoryPointers| 和 |selectivePointers| 的连接。
  5. 将 |groupDefinitions| 初始化为一个映射,包含以下条目:键为字符串 `"mandatory"`,值为 |mandatoryPointers|;键为字符串 `"selective"`,值为 |selectivePointers|;键为字符串 `"combined"`,值为 |combinedPointers|。
  6. 将 |groups| 和 |labelMap| 初始化为调用 [[DI-ECDSA]] 规范中 第 3.3.16 节 canonicalizeAndGroup 算法的结果,传递 |document|、|labelMapFactoryFunction|、|groupDefinitions| 和任何自定义 JSON-LD API 选项。注意:此步骤将文档转换为一个规范化的 N-Quads 数组,其顺序基于应用了 HMAC 的空白节点标识符进行了打乱,并根据 JSON 指针对 N-Quad 字符串进行分组。
  7. 计算强制性索引(mandatory indexes),相对于它们在组合声明列表中的位置,即找到强制性声明在组合声明列表中出现的位置。以下是执行此操作的一种方法:
    1. 将 |mandatoryIndexes| 初始化为空数组。将 |mandatoryMatch| 设置为 |groups.mandatory.matching| 映射;将 |combinedMatch| 设置为 |groups.combined.matching|;将 |combinedIndexes| 设置为仅包含 |combinedMatch| 映射键的有序数组。
    2. 对于 |mandatoryMatch| 映射中的每个键,在 |combinedIndexes| 数组中找到其索引位置(例如,`combinedIndexes.indexOf(key)`),并将此值添加到 |mandatoryIndexes| 数组中。
  8. 计算选择性索引(selective indexes),相对于它们在非强制性声明列表中的位置,即找到选定声明在非强制性声明列表中出现的位置。以下是执行此操作的一种方法:
    1. 将 |selectiveIndexes| 初始化为空数组。将 |selectiveMatch| 设置为 |groups.selective.matching| 映射;将 |mandatoryNonMatch| 设置为 |groups.mandatory.nonMatching| 映射;将 |nonMandatoryIndexes| 设置为仅包含 |mandatoryNonMatch| 映射键的有序数组。
    2. 对于 |selectiveMatch| 映射中的每个键,在 |nonMandatoryIndexes| 数组中找到其索引位置(例如,`nonMandatoryIndexes.indexOf(key)`),并将此值添加到 |selectiveIndexes| 数组中。
  9. 将 |bbsMessages| 初始化为一个字节数组的数组,其中包含 |nonMandatory| 字符串数组中使用 UTF-8 字符编码编码的值。
  10. 根据 |featureOption| 参数的值,使用以下适当的过程计算 |bbsProof| 的值:
    1. 如果 |featureOption| 等于 `"baseline"`,将 `bbsProof` 设置为 [[CFRG-BBS-SIGNATURE]] 中 `ProofGen` 过程计算的值,即: `ProofGen(PK, signature, header, ph, messages, disclosed_indexes)`, 其中 `PK` 是原始发行方的公钥,`signature` 是 `bbsSignature`,`header` 是 `bbsHeader`,`ph` 是 `presentationHeader`,`messages` 是 `bbsMessages`,`disclosed_indexes` 是 `selectiveIndexes`。
    2. 如果 |featureOption| 等于 `"anonymous_holder_binding"`,将 `bbsProof` 设置为 [[CFRG-Blind-BBS-Signature]] 中 `BlindProofGen` 过程计算的值,其中 |PK| 是原始发行方的公钥,|signature| 是 |bbsSignature|,|header| 是 |bbsHeader|,|ph| 是 |presentationHeader|,|messages| 是 |bbsMessages|,|disclosed_indexes| 是 |selectiveIndexes|,以及 `commitment_with_proof`。持有方还将提供其 |holder_secret| 和用于计算 `commitment_with_proof` 的 |proverBlind|。这是 匿名持有方绑定功能选项。
    3. 如果 |featureOption| 等于 `"pseudonym"`,使用 [[CFRG-Pseudonym-BBS-Signature]] 中的“验证和完成”操作,传递一个空的 |committed_messages| 数组,同时验证 |bbsSignature| 并计算 |nym_secret| 值。此操作使用 |prover_nym|、|signer_nym_entropy| 和 |secret_prover_blind|。

      确定 |nym_domain|。这可能由验证方指定或由持有方设置,具体取决于使用场景。使用 [[CFRG-Pseudonym-BBS-Signature]] 中的“带有假名的证明生成”操作生成派生证明。此操作的输入包括原始发行方的公钥 |PK|、|bbsSignature|、|bbsHeader|、|presentationHeader|、|bbsMessages|、|selectiveIndexes|、|nym_secret|、|nym_domain|、一个空数组作为 |committed_messages|,以及 |secret_prover_blind|。除了提供分配给 |bbsProof| 的原始加密证明值外,它还返回 |pseudonym|。
    4. 如果 |featureOption| 等于 `"holder_binding_pseudonym"`,使用 [[CFRG-Pseudonym-BBS-Signature]] 中的“验证和完成”操作,传递一个包含 |holder_secret| 作为唯一值的 |committed_messages| 数组,同时验证 |bbsSignature| 并计算 |nym_secret| 值。此操作使用 |prover_nym|、|signer_nym_entropy| 和 |secret_prover_blind|。

      确定 |nym_domain|。这可能由验证方指定或由持有方设置,具体取决于使用场景。使用 [[CFRG-Pseudonym-BBS-Signature]] 中的“带有假名的证明生成”操作生成派生证明。此操作的输入包括原始发行方的公钥 |PK|、|bbsSignature|、|bbsHeader|、|presentationHeader|、|bbsMessages|、|selectiveIndexes|、|nym_secret|、|nym_domain|、|committed_messages| 数组的唯一值 |holder_secret|,以及 |secret_prover_blind|。除了提供分配给 |bbsProof| 的原始加密证明值外,它还返回 |pseudonym|。
  11. 如果 |featureOption| 等于 `"anonymous_holder_binding"`、`"pseudonym"` 或 `"holder_binding_pseudonym"`,将 |lengthBBSMessages| 参数设置为 |bbsMessages| 数组的长度。
  12. 将 |revealDocument| 初始化为 [[DI-ECDSA]] 中“selectJsonLd”算法的结果,传递 `document` 和 `combinedPointers` 作为 `pointers`。
  13. 对连接的 |combinedGroup|.|deskolemizedNQuads| 运行 RDF 数据集规范化算法 [[RDF-CANON]],传递任何自定义选项,并获取规范化空白节点标识符映射 |canonicalIdMap|。注意:此映射包括验证方在规范化披露文档时生成的规范化空白节点标识符。
  14. 将 |verifierLabelMap| 初始化为空映射。此映射将验证方在规范化披露文档时生成的规范化空白节点标识符映射到基础证明中最初签名的空白节点标识符。
  15. 对于 `canonicalIdMap` 中的每个键(`inputLabel`)和值(`verifierLabel`):
    1. 向 `verifierLabelMap` 添加一个条目,使用 `verifierLabel` 作为键,并使用 `labelMap` 中与 `inputLabel` 关联的值作为值。
  16. 返回一个对象,其属性包括 |bbsProof|、|labelMap| 的 "verifierLabelMap"、|mandatoryIndexes|、|selectiveIndexes|、|revealDocument|、|pseudonym|,以及(如果计算)|lengthBBSMessages|。

压缩标签映射

以下算法用于压缩标签映射。所需输入是标签映射(|labelMap|)。输出是一个压缩标签映射

  1. 将 `map` 初始化为空映射。
  2. 对于 `labelMap` 中的每个条目(`k`,`v`):
    1. 向 `map` 添加一个条目,其键是从 `k` 中 "c14n" 前缀后解析出的十进制整数,其值是从 `v` 中 "b" 前缀后解析出的十进制整数。
  3. 返回 `map` 作为压缩标签映射

解压缩标签映射

以下算法用于解压缩标签映射。所需输入是压缩标签映射(|compressedLabelMap|)。输出是一个解压缩标签映射

  1. 将 `map` 初始化为空映射。
  2. 对于 `compressedLabelMap` 中的每个条目(`k`,`v`):
    1. 向 `map` 添加一个条目,其键为在 `k` 前添加前缀 "c14n",其值为在 `v` 前添加前缀 "b"。
  3. 返回 `map` 作为解压缩标签映射

序列化派生证明值

以下算法用于序列化派生证明值。所需输入包括 BBS 证明(|bbsProof|)、标签映射(|labelMap|)、强制性索引数组(|mandatoryIndexes|)、选择性索引数组(|selectiveIndexes|)、BBS 展示头部(|presentationHeader|)、|featureOption| 指示器,以及根据 |featureOption| 值可能需要的 |nym_domain|、|pseudonym| 和/或 |lengthBBSMessages| 值。输出是一个序列化为字节字符串的单一派生证明值。

  1. 将 `compressedLabelMap` 初始化为调用第 节中的算法的结果,传递 `labelMap` 作为参数。
  2. 根据 |featureOption| 的值执行以下操作:
    1. 如果 |featureOption| 等于 `"baseline"`:
      1. 将 |proofValue| 初始化为以披露证明头部字节 `0xd9`、`0x5d` 和 `0x03` 开头。
      2. 将 |components| 初始化为一个数组,包含以下值:|bbsProof|、|compressedLabelMap|、|mandatoryIndexes|、|selectiveIndexes| 和 |presentationHeader|。
    2. 如果 |featureOption| 等于 `"anonymous_holder_binding"`:
      1. 将 |proofValue| 初始化为以披露证明头部字节 `0xd9`、`0x5d` 和 `0x05` 开头。
      2. 将 |components| 初始化为一个数组,包含以下值:|bbsProof|、|compressedLabelMap|、|mandatoryIndexes|、|selectiveIndexes|、|presentationHeader| 和 |lengthBBSMessages|。
    3. 如果 |featureOption| 等于 `"pseudonym"`:
      1. 将 |proofValue| 初始化为以披露证明头部字节 `0xd9`、`0x5d` 和 `0x07` 开头。
      2. 将 |components| 初始化为一个数组,包含以下值:|bbsProof|、|compressedLabelMap|、|mandatoryIndexes|、|selectiveIndexes|、|presentationHeader|、|nym_domain|、|pseudonym| 和 |lengthBBSMessages|。
    4. 如果 |featureOption| 等于 `"holder_binding_pseudonym"`:
      1. 将 |proofValue| 初始化为以披露证明头部字节 `0xd9`、`0x5d` 和 `0x09` 开头。
      2. 将 |components| 初始化为一个数组,包含以下值:|bbsProof|、|compressedLabelMap|、|mandatoryIndexes|、|selectiveIndexes|、|presentationHeader|、|nym_domain|、|pseudonym| 和 |lengthBBSMessages|。
  3. 根据 [[RFC8949]] 对 |components| 进行 CBOR 编码,其中 CBOR 标记不得用于任何 |components|。将生成的编码值附加到 |proofValue|。
  4. 返回一个以 "`u`" 开头并以 |proofValue| 的 base64url-no-pad 编码值结尾的字符串,作为派生证明

解析派生证明值

以下算法解析派生证明值的组成部分。所需输入为一个派生证明值(|proofValue|)。输出是一个单一的派生证明值对象,包含六到九个元素,名称为 "bbsProof"、"labelMap"、"mandatoryIndexes"、"selectiveIndexes"、"presentationHeader"、"featureOption",以及根据 |featureOption| 参数的值可能包含的 "nym_domain"、"pseudonym" 和/或 "lengthBBSMessages"。

  1. 如果 `proofValue` 字符串未以 u (U+0075, LATIN SMALL LETTER U) 开头,表明它不是 `multibase-base64url-no-pad-encoded` 值,则必须引发错误,并应传递错误类型 PROOF_VERIFICATION_ERROR
  2. 将 |decodedProofValue| 初始化为对 `proofValue` 中前导 `u` 后的子字符串进行 base64url-no-pad 解码的结果。
  3. 检查 BBS 披露证明是否以允许的头部值开头,并根据以下规则设置 |featureOption| 变量:
    1. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x03` 开头,则将 |featureOption| 设置为 `"baseline"`。
    2. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x05` 开头,则将 |featureOption| 设置为 `"anonymous_holder_binding"`。
    3. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x07` 开头,则将 |featureOption| 设置为 `"pseudonym"`。
    4. 如果 |decodedProofValue| 以字节 `0xd9`、`0x5d` 和 `0x09` 开头,则将 |featureOption| 设置为 `"holder_binding_pseudonym"`。
  4. 将 `components` 初始化为对三字节 BBS 披露证明头部后面的字节进行 CBOR 解码的结果数组。如果结果不是包含五、六、七或八个元素的数组,则必须引发错误,并应传递错误类型 PROOF_VERIFICATION_ERROR
  5. 使用第 节中的算法,将 `components` 的第二个元素替换为调用该算法时传递 `components` 的现有第二个元素(`compressedLabelMap`)的结果。
  6. 返回一个派生证明值对象,其属性设置为五、六、七或八个元素,分别使用名称 "bbsProof"、"labelMap"、"mandatoryIndexes"、"selectiveIndexes"、"presentationHeader",以及可选的 "nym_domain"、"pseudonym" 和/或 "lengthBBSMessages"。此外,添加 |featureOption| 及其值到对象中。

创建验证数据

以下算法用于创建验证 BBS 保护的可验证凭证所需的数据。输入包括一个 JSON-LD 文档(|document|)、一个 BBS 披露证明(|proof|)以及任何自定义 JSON-LD API 选项(如文档加载器)。输出是一个单一的验证数据对象,包含以下字段:|bbsProof|、|proofHash|、|mandatoryHash|、|selectiveIndexes|、|presentationHeader|、|nonMandatory|、|featureOption|,以及可能的 |pseudonym| 和/或 |lengthBBSMessages|。

  1. 将 |proofHash| 初始化为对证明选项执行 RDF 数据集规范化 [[RDF-CANON]] 的结果,即文档中去除 |proofValue| 的证明部分。使用的哈希算法与签名算法相同,即 SHA-256。注意:此步骤可以并行执行,只需在算法需要使用 |proofHash| 值之前完成即可。
  2. 将 |bbsProof|、|labelMap|、|mandatoryIndexes|、|selectiveIndexes|、|presentationHeader|、|featureOption| 以及可能的 |pseudonym| 和/或 |lengthBBSMessages| 初始化为调用第 节中的算法时返回的对象中与其属性名称匹配的值,传递 |proof| 中的 |proofValue|。
  3. 将 |labelMapFactoryFunction| 初始化为调用 [[DI-ECDSA]] 的 "`createLabelMapFunction`" 算法的结果,传递 |labelMap|。
  4. 将 |nquads| 初始化为调用 [[DI-ECDSA]] 的 "`labelReplacementCanonicalize`" 算法的结果,传递 |document|、|labelMapFactoryFunction| 和任何自定义 JSON-LD API 选项。注意:此步骤将文档转换为一个基于 |labelMap| 的伪随机空白节点标识符的规范化 N-Quads 数组。
  5. 将 |mandatory| 初始化为空数组。
  6. 将 |nonMandatory| 初始化为空数组。
  7. 对于 |nquads| 中的每个条目(|index|,|nq|),将 N-Quads 分为强制性和非强制性类别:
    1. 如果 |mandatoryIndexes| 包含 |index|,将 |nq| 添加到 |mandatory|。
    2. 否则,将 |nq| 添加到 |nonMandatory|。
  8. 将 |mandatoryHash| 初始化为调用 "`hashMandatory`" 原语的结果,传递 |mandatory|。
  9. 返回一个对象,其属性与 |baseSignature|、|proofHash|、|nonMandatory|、|mandatoryHash|、|selectiveIndexes|、|featureOption| 以及可能的 |pseudonym| 和/或 |lengthBBSMessages| 匹配。

bbs-2023

`bbs-2023` 加密套件接收一个输入文档,使用 RDF 数据集规范化算法 [[RDF-CANON]] 对文档进行规范化,然后应用一系列转换和加密操作,最终生成一个数据完整性证明。本节中的算法还包括此类数据完整性证明的验证。

创建基础证明 (bbs-2023)

以下算法指定了如何根据未加密数据文档创建[=数据完整性证明=]。所需输入包括一个未加密数据文档([=map=] |unsecuredDocument|)、一组证明选项([=map=] |options|)、一个强制性 JSON 指针数组(|mandatoryPointers|)、一个 |featureOption| 指示参数,以及根据 |featureOption| 的值可能需要的 |commitment_with_proof| 字节数组。输出是一个[=数据完整性证明=]([=map=])或错误。

|featureOption| 参数用于指示是否使用了可选功能。它可以取以下值之一:`"baseline"`、`"anonymous_holder_binding"`、`"pseudonym"` 或 `"holder_binding_pseudonym"`。注意,`"baseline"` 表示未使用任何可选功能。如果 |featureOption| 设置为 `"anonymous_holder_binding"`、`"pseudonym"` 或 `"holder_binding_pseudonym"`,则必须提供 |commitment_with_proof| 输入。如果 |featureOption| 设置为 `"pseudonym"` 或 `"holder_binding_pseudonym"`,则必须提供 |signer_nym_entropy| 输入。

  1. 将 |proof| 初始化为证明选项 |options| 的克隆。
  2. 将 |proofConfig| 初始化为运行第 [[[#base-proof-configuration-bbs-2023]]] 节中的算法并传递 |options| 作为参数的结果。
  3. 将 |transformedData| 初始化为运行第 [[[#base-proof-transformation-bbs-2023]]] 节中的算法并传递 |unsecuredDocument|、|proofConfig| 和 |options| 作为参数的结果。
  4. 将 |hashData| 初始化为运行第 [[[#base-proof-hashing-bbs-2023]]] 节中的算法并传递 |transformedData| 和 |proofConfig| 作为参数的结果。
  5. 将 |proofBytes| 初始化为运行第 [[[#base-proof-serialization-bbs-2023]]] 节中的算法并传递 |hashData|、|options|、|featureOption| 以及(如果需要)|commitment_with_proof| 作为参数的结果。
  6. 将 |proof|.|proofValue| 设置为 |proofBytes| 的base64url 编码的 Multibase 值
  7. 返回 |proof| 作为[=数据完整性证明=]。

基础证明转换 (bbs-2023)

以下算法指定了如何将未加密的输入文档转换为一个已转换的文档,以便作为输入提供给第 节中的哈希算法。

此算法所需的输入包括一个未加密数据文档(|unsecuredDocument|)和转换选项(|options|)。转换选项必须包含加密套件的类型标识符(|type|)、加密套件标识符(|cryptosuite|)和验证方法(|verificationMethod|)。转换选项必须包含一个强制性 JSON 指针数组(|mandatoryPointers|),并且可以包含其他选项,例如 JSON-LD 文档加载器。输出是一个已转换数据文档。每当此算法对字符串进行编码时,必须使用 UTF-8 编码。

  1. 将 |hmac| 初始化为一个 HMAC API,使用本地生成且可导出的 HMAC 密钥。HMAC 使用与签名算法相同的哈希算法,即 SHA-256。根据 [[RFC2104]] 的建议,HMAC 密钥的长度必须与摘要大小相同;对于 SHA-256,这是 256 位或 32 字节。
  2. 将 `labelMapFactoryFunction` 初始化为调用 `createShuffledIdLabelMapFunction` 算法并传递 `hmac` 作为 `HMAC` 的结果。
  3. 将 `groupDefinitions` 初始化为一个映射,其中包含一个键为字符串 "`mandatory`",值为 |mandatoryPointers| 的条目。
  4. 将 `groups` 初始化为调用 [[DI-ECDSA]] 规范第 3.3.16 节 canonicalizeAndGroup 算法的结果,传递 `labelMapFactoryFunction`、`groupDefinitions`、`unsecuredDocument` 作为 `document`,以及任何自定义 JSON-LD API 选项。注意:此步骤将文档转换为一个基于 `hmac` 应用到空白节点标识符的规范化 N-Quads 数组,并根据 JSON 指针的选择对 N-Quad 字符串进行分组。
  5. 将 `mandatory` 初始化为 `groups.mandatory.matching` 映射中的值。
  6. 将 `nonMandatory` 初始化为 `groups.mandatory.nonMatching` 映射中的值。
  7. 将 `hmacKey` 初始化为从 `hmac` 导出的 HMAC 密钥的结果。
  8. 返回一个对象,其中 "`mandatoryPointers`" 设置为 `mandatoryPointers`,"`mandatory`" 设置为 `mandatory`,"`nonMandatory`" 设置为 `nonMandatory`,"`hmacKey`" 设置为 `hmacKey`。

基础证明哈希 (bbs-2023)

以下算法指定了如何对转换后的数据文档证明配置进行加密哈希处理,以生成可作为输入提供给第 节中算法的加密哈希数据。

此算法所需的输入包括一个转换后的数据文档(|transformedDocument|)和规范化的证明配置(|canonicalProofConfig|)。输出是一个以对象表示的哈希数据值。

  1. 将 `proofHash` 初始化为对 `canonicalProofConfig` 调用 RDF 数据集规范化算法 [[RDF-CANON]] 的结果,然后使用与签名算法相同的哈希算法(即 SHA-256)对结果进行加密哈希处理。注意:此步骤可以并行执行,只需在算法结束前完成即可,因为结果是返回值的一部分。
  2. 将 `mandatoryHash` 初始化为调用 [[DI-ECDSA]] 规范第 3.3.17 节 hashMandatoryNQuads 算法的结果,传递 |transformedDocument|.`mandatory` 并使用 SHA-256 算法。
  3. 将 `hashData` 初始化为 |transformedDocument| 的深拷贝,并将 `proofHash` 添加为 "`proofHash`" 属性,将 `mandatoryHash` 添加为 "`mandatoryHash`" 属性。
  4. 返回 `hashData` 作为哈希数据

基础证明配置 (bbs-2023)

以下算法指定了如何从一组证明选项生成证明配置,以用作基础证明哈希算法的输入。

此算法所需的输入包括证明选项(|options|)和未加密数据文档(|unsecuredDocument|)。证明选项必须包含加密套件的类型标识符(|type|)和加密套件标识符(|cryptosuite|)。输出是一个证明配置对象。

  1. 将 |proofConfig| 设置为 |options| 对象的克隆。
  2. 如果 |proofConfig|.|type| 未设置为 `DataIntegrityProof` 或 |proofConfig|.|cryptosuite| 未设置为 `bbs-2023`,则必须引发错误,并应传递错误类型 PROOF_GENERATION_ERROR
  3. 如果 |proofConfig|.|created| 已设置且值不是有效的 [[XMLSCHEMA11-2]] 日期时间,则必须引发错误,并应传递错误类型 PROOF_GENERATION_ERROR
  4. 将 |proofConfig|.@context 设置为 |unsecuredDocument|.@context
  5. 将 |canonicalProofConfig| 设置为对 |proofConfig| 应用 RDF 数据集规范化算法 [[RDF-CANON]] 的结果。
  6. 返回 |canonicalProofConfig|。

基础证明序列化 (bbs-2023)

以下算法由 BBS 保护的可验证凭证的发行方调用,指定如何创建基础证明。基础证明仅提供给持有方,持有方负责从中生成派生证明,并在证明中仅向验证方披露选择性披露的细节。此算法设计用于与数据完整性 [[VC-DATA-INTEGRITY]] 规范中定义的算法结合使用, 第 4 节:算法。所需输入包括加密哈希数据(|hashData|)、|featureOption|,以及(如果需要)|commitment_with_proof|。 如果 |featureOption| 设置为 `"anonymous_holder_binding"`、`"pseudonym"` 或 `"holder_binding_pseudonym"`,则必须提供 |commitment_with_proof| 输入;如果未提供,则必须引发错误,并应传递错误类型 PROOF_GENERATION_ERROR。 如果 |featureOption| 设置为 `"pseudonym"` 或 `"holder_binding_pseudonym"`,则必须提供 |signer_nym_entropy| 输入;如果未提供,则必须引发错误,并应传递错误类型 PROOF_GENERATION_ERROR。 输出是一个以字节表示的单一数字证明值。

  1. 将 `proofHash`、`mandatoryPointers`、`mandatoryHash`、`nonMandatory` 和 `hmacKey` 初始化为 |hashData| 中与其属性名称关联的值。
  2. 将 `bbsHeader` 初始化为 `proofHash` 和 `mandatoryHash` 按顺序连接的结果。
  3. 将 `bbsMessages` 初始化为一个字节数组的数组,其中包含 `nonMandatory` 字符串数组中的值,使用 UTF-8 字符编码进行编码。
  4. 根据 |featureOption| 的值,使用以下过程计算 `bbsSignature`:
    1. 如果 |featureOption| 等于 `"baseline"`,使用 [[CFRG-BBS-Signature]] 的 `Sign` 过程计算 `bbsSignature`,使用适当的密钥材料,|bbsHeader| 作为 `header`,|bbsMessages| 作为 `messages`。
    2. 如果 |featureOption| 等于 `"anonymous_holder_binding"`,使用 [[CFRG-Blind-BBS-Signature]] 的 `BlindSign` 过程计算 `bbsSignature`,使用适当的密钥材料,|commitment_with_proof| 作为 `commitment_with_proof`,|bbsHeader| 作为 `header`,|bbsMessages| 作为 `messages`。这提供了 匿名持有方绑定功能。
    3. 如果 |featureOption| 等于 `"pseudonym"` 或 `"holder_binding_pseudonym"`,发行方生成一个加密随机值作为 |signer_nym_entropy|,并使用 [[CFRG-Pseudonym-BBS-Signature]] 的“盲发行”操作计算 `bbsSignature`,使用适当的密钥材料,|bbsHeader| 作为 `header`,|bbsMessages| 作为 `messages`,|commitment_with_proof| 作为 `commitment_with_proof`,以及 |signer_nym_entropy| 值。 如果发行方可能需要重新向该持有方重新发行绑定到相同 |nym_secret| 的凭证,则应保留 |signer_nym_entropy| 值;否则,可以丢弃此值。

      这提供了 凭证绑定的化名持有方绑定和化名功能。
  5. 将 `proofValue` 初始化为调用第 节中的算法的结果,传递 |bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey|、|mandatoryPointers|、|featureOption|,以及根据 |featureOption| 值可能需要的 |signer_nym_entropy| 作为参数。

    注意:`publicKey` 是一个字节数组,按照 [[CFRG-BBS-SIGNATURE]] 编码的公钥。
  6. 返回 `proofValue` 作为数字证明

添加派生证明 (bbs-2023)

以下算法由持有 `bbs-2023` 保护的可验证凭证的持有方调用,用于创建选择性披露的派生证明。派生证明将提供给验证方。输入包括一个 JSON-LD 文档(|document|)、一个 BBS 基础证明(|proof|)、一个用于选择性披露声明的 JSON 指针数组(|selectivePointers|)、一个可选的 BBS |presentationHeader|(字节数组)、一个 |featureOption| 参数、支持所选 |featureOption| 的附加参数(见下文),以及任何自定义 JSON-LD API 选项(如文档加载器)。输出是一个以对象表示的单一选择性披露文档值。

如果 |featureOption| 等于 `"anonymous_holder_binding"`,则必须提供附加输入 |holderSecret| 和 |proverBlind|。这些值由持有方预先计算。有关背景信息,请参阅匿名持有方绑定

如果 |featureOption| 等于 `"pseudonym"`,则必须提供附加输入 |prover_nym| 和 |proverBlind|(两者均由持有方知晓),以及 |nym_dofmain|(由持有方设置或由验证方传递给持有方)。有关背景信息,请参阅凭证绑定的化名

如果 |featureOption| 等于 `"holder_binding_pseudonym"`,则必须提供附加输入 |holder_secret|、|prover_nym| 和 |proverBlind|(均由持有方知晓),以及 |nym_dofmain|(由持有方设置或由验证方传递给持有方)。有关背景信息,请参阅持有方绑定和化名

  1. 将 |bbsProof|、|labelMap|、|mandatoryIndexes|、|selectiveIndexes| 和 |revealDocument| 初始化为调用第 节中的算法时返回的对象中与其属性名称匹配的值,传递 |document|、|proof|、|selectivePointers|、|presentationHeader|、|featureOption|、基于 |featureOption| 的所需附加输入,以及任何自定义 JSON-LD API 选项(如文档加载器)。
  2. 将 |newProof| 初始化为 |proof| 的浅拷贝。
  3. 用调用第 节中的算法的结果替换 |newProof| 中的 |proofValue|,传递 |bbsProof|、|labelMap|、|mandatoryIndexes|、|selectiveIndexes|、|featureOption| 以及 |featureOption| 指定的任何所需输入。
  4. 将 |revealDocument| 中 "`proof`" 属性的值设置为 |newProof|。
  5. 返回 |revealDocument| 作为选择性披露文档

验证派生证明 (bbs-2023)

以下算法指定了如何验证给定安全数据文档的[=数据完整性证明=]。所需输入是一个安全数据文档([=map=] |securedDocument|)。此算法返回一个验证结果,它是一个[=struct=],其[=struct/items=] 包括:

verified
`true` 或 `false`
verifiedDocument
Null,如果 [=verification result/verified=] 为 `false`;否则为一个[=未加密数据文档=]。

要验证派生证明,请执行以下步骤:

  1. 令 |publicKeyBytes| 为根据数据完整性 [[VC-DATA-INTEGRITY]] 规范中第 4 节:检索验证方法描述的方式,检索与 |proof|.|verificationMethod| 值关联的公钥字节的结果。
  2. 令 |unsecuredDocument| 为 |securedDocument| 的副本,并移除其 `proof` 值。
  3. 令 |proof| 为 |securedDocument|.|proof| 的值。
  4. 将 |bbsProof|、|proofHash|、|mandatoryHash|、|selectiveIndexes|、|presentationHeader|、|nonMandatory|、|featureOption| 以及可能的 |lengthBBSMessages| 和/或 |pseudonym| 初始化为调用第 节中的算法时返回的对象中与其属性名称匹配的值,传递 |unsecuredDocument|、|proof| 以及任何自定义 JSON-LD API 选项(如文档加载器)。
  5. 将 |bbsHeader| 初始化为按顺序连接的 |proofHash| 和 |mandatoryHash|。将 |disclosedMessages| 初始化为从 |nonMandatory| 数组的元素的 UTF-8 编码中获取的字节数组。
  6. 根据 |featureOption| 的值,初始化 |verified| 为以下验证算法的结果:
    1. 如果 |featureOption| 等于 `"baseline"`,将 |verified| 初始化为应用 [[CFRG-BBS-SIGNATURE]] 的验证算法 `ProofVerify(PK, proof, header, ph, disclosed_messages, disclosed_indexes)` 的结果,其中 `PK` 设置为原始发行方的公钥,`proof` 设置为 `bbsProof`,`header` 设置为 `bbsHeader`,`disclosed_messages` 设置为 `disclosedMessages`,`ph` 设置为 `presentationHeader`,`disclosed_indexes` 设置为 `selectiveIndexes`。
    2. 如果 |featureOption| 等于 `"anonymous_holder_binding"`,将 |verified| 初始化为应用 [[CFRG-Blind-BBS-Signature]] 的验证算法 `ProofVerify` 的结果,使用 |lengthBBSMessages| 作为 `"L"` 参数。 待 IETF API 最终确定后更新。
    3. 如果 |featureOption| 等于 `"pseudonym"` 或 `"holder_binding_pseudonym"`,将 |verified| 初始化为应用 [[CFRG-Pseudonym-BBS-Signature]] 的“带化名的证明验证”操作的结果,使用 |lengthBBSMessages| 作为 `"L"` 参数,并使用空的 |committed_messages| 数组。 待 IETF API 最终确定后更新。
  7. 返回一个 [=验证结果=],其 [=struct/items=] 包括:
    [=verified=]
    |verified|
    [=verifiedDocument=]
    |unsecuredDocument| 如果 |verified| 为 `true`,否则为 Null

可选功能

BBS 签名的加密特性允许支持高级功能的变体。本规范仅限于支持这些增强功能中最相关的部分,我们将在以下章节中进行说明。变量 |commitment_with_proof|、|holder_secret|、|prover_nym|、|signer_nym_entropy| 和 |pseudonym| 与这些功能相关,而在 BBS 签名和证明中并不需要这些变量。

本节中描述的可选 BBS 功能以及本规范中的算法包含的功能存在风险,如果其各自的规范未能在 IETF 的时间表内达到 RFC 状态,或者每个可选功能没有至少两个独立的实现,这些功能将在本规范最终确定之前被移除。

匿名持有方绑定

此功能在签发时将带有基础证明的文档绑定到仅持有方知道的一个秘密,以确保只有该持有方能够生成可验证的带有派生证明的披露文档。例如,如果攻击者获得了带有基础证明的文档,他们无法创建可验证的带有派生证明的披露文档。

为了实现此功能,持有方生成一个 |holder_secret| 值,该值通常应至少为 32 字节长并通过加密随机生成。此值不会被持有方共享。相反,持有方生成一个承诺以及一个关于此值的零知识证明,使用 [[CFRG-Blind-BBS-Signature]] 的“承诺计算”操作。此计算涉及加密随机值,并计算出 |commitment_with_proof| 和 |secret_prover_blind| 值。|commitment_with_proof| 被传递给签发方,而 |secret_prover_blind| 被持有方保密并用于生成派生证明。 请注意,持有方可以多次运行“承诺计算”操作,以生成可用于不同签发方的不可链接的 |commitment_with_proof| 值。

签发方在收到 |commitment_with_proof| 后,按照本规范的程序,使用 [[CFRG-Blind-BBS-Signature]] 的“盲签名生成”操作生成文档的基础证明(签名),并使用持有方提供的 |commitment_with_proof|。

当持有方希望创建带有派生证明的选择性披露文档时,他们使用本规范的程序以及 [[CFRG-Blind-BBS-Signature]] 的“证明生成”操作。他们将其 |holder_secret| 作为 |committed messages| 数组中的唯一“消息”,并提供其 |secret_prover_blind|。

带有派生证明的披露文档的验证使用本规范的程序以及 [[CFRG-Blind-BBS-Signature]] 的“证明验证”操作。

凭证绑定的化名

本文件中指定的 BBS 签名的可验证凭证允许选择性披露和不可链接的加密证明工件。所谓“不可链接”,是指派生证明中的加密信息无法与其他证明或原始签名相关联。这意味着验证方无法确定持有方是否以前展示过相同的凭证(使用不同的证明实例),也无法断言某种身份。凭证绑定的化名提供了一种隐私保护机制,允许加密化名的有限链接性。此类化名可以由持有方单独确定,也可以由持有方和验证方共同确定。

这种加密化名(加密标识符/名称)由两部分组成。第一部分 |nym_secret| 由持有方指定并仅为持有方所知;第二部分 |nym_domain| 可以由持有方或验证方指定,并将在持有方和验证方之间共享。签发方在签发过程中将凭证绑定到 |nym_secret|。持有方随后可以从 |nym_secret| 计算化名,并向验证方证明这些化名绑定到他们正在展示的凭证。由相同 |nym_secret| 和不同 |nym_domain| 值计算出的加密化名是不可链接的。

持有方可能选择一个 |nym_domain|,为自己提供某种类型的公共论坛化名,例如选择 |nym_domain| = "Mark Twain"。持有方从此 |nym_domain| 和其 |nym_secret| 计算出的加密化名本质上是唯一的,且没有同时知道 |nym_secret| 和拥有绑定到化名的基础可验证凭证的实体能够断言此化名身份。请注意,(|nym_domain|, 化名) 的二元组必须与派生凭证一起发送以断言此化名身份。

在另一种情况下,持有方可能正在使用验证方的服务,而验证方希望跟踪持有方的访问时间或监控其资源使用情况。在这种情况下,验证方选择持有方在展示其派生凭证时需要使用的 |nym_domain|。例如,验证方可能指定一个与其 DNS 域绑定的公共 |nym_domain|(例如 `"www.nym.example"`)供持有方使用。验证方还可以通过定期更改 |nym_domain|(例如将其与日期绑定,`"www.nym.example/2025-01-02"`)来展示其支持某种数据最小化的能力。本规范不规定 |nym_domain| 的值。

最后,为防止恶意持有方获取其他持有方的 |nym_secret| 并获得绑定到该值的凭证,[[CFRG-Pseudonym-BBS-Signature]] 的操作要求签发方在签名生成过程中添加一个随机化因子 |signer_nym_entropy|,该因子与持有方部分 |prover_nym| 安全地“混合”。这会生成一个 |nym_secret|,签发方可以为其提供加密保证,确保其唯一性并供持有方使用。

凭证绑定的化名的创建和使用概述如下步骤。

  1. 持有方创建一个安全值,称为 |prover_nym|,该值应至少为 32 字节长并以加密随机方式生成。然后,他们使用 [[CFRG-Pseudonym-BBS-Signature]] 的“承诺”操作(`Commitment`),并使用空的 |committed_messages| 数组来计算 |commitment_with_proof| 和 |secret_prover_blind|。持有方将 |commitment_with_proof| 发送给签发方以请求凭证,但从不披露 |prover_nym| 和 |secret_prover_blind|,并将其保留以备后用。
  2. 签发方收到持有方的凭证请求(带有绑定化名,|featureOption| 等于 `"pseudonym"`),以及 |commitment_with_proof|。签发方为 |signer_nym_entropy| 生成一个加密随机值,并使用 [[CFRG-Pseudonym-BBS-Signature]] 的“盲发行”操作生成基础证明。基础证明将包含 |signer_nym_entropy| 值。如果签发方可能需要重新向该持有方重新发行绑定到相同 |nym_secret| 的凭证,则应保留 |signer_nym_entropy| 值;否则,可以丢弃此值。
  3. 在收到带有绑定化名的凭证后,持有方使用本规范中的程序以及 [[CFRG-Pseudonym-BBS-Signature]] 的“验证和最终化”操作(`Verification and Finalization`),并使用空的 |committed_messages| 数组,同时验证签名并计算 |nym_secret| 值。此操作使用 |prover_nym|、|signer_nym_entropy| 和 |secret_prover_blind| 值等。如果正在使用第三方监控,则需要将 |nym_secret| 值安全地共享给监控组织。
  4. 当持有方希望生成绑定到化名的派生证明时,他们需要确定 |nym_domain|。如前所述,这可能由验证方指定,也可能由持有方设置,具体取决于使用场景。然后,他们使用本规范中的程序以及 [[CFRG-Pseudonym-BBS-Signature]] 的“带化名的证明生成”操作(`Proof Generation with Pseudonym`)生成派生证明。此操作将 |nym_secret|、|nym_domain|、空的 |committed_messages| 数组和 |secret_prover_blind| 等作为输入。除了提供原始加密证明值外,它还返回包含在派生证明中的 |pseudonym| 值。
  5. 当验证方收到带有绑定化名的派生证明时,他们使用本规范中的程序以及 [[CFRG-Pseudonym-BBS-Signature]] 的“带化名的证明验证”操作(`Proof Verification with Pseudonym`)验证派生证明。请注意,这些程序还将验证指定的 |nym_domain| 是否用于计算 |pseudonym|。

持有方绑定和化名

匿名持有方绑定和凭证绑定的化名在某种意义上是正交的功能,持有方和凭证生态系统可能希望同时使用这两种功能。例如,持有方可能希望将可验证凭证绑定到一个 |holder_secret|,以便只有知道该值的持有方才能从基础证明生成派生证明,并将一个 |nym_secret| 绑定到基础证明,以便化名可以绑定到派生证明。这对应于 |featureOption| 等于 `"holder_binding_pseudonym"`。

以下是同时使用匿名持有方绑定和凭证绑定化名的创建和使用步骤概述。

  1. 持有方创建两个安全值,分别称为 |holder_secret| 和 |prover_nym|,它们应至少为 32 字节长,并以加密随机方式生成。然后,他们使用 [[CFRG-Pseudonym-BBS-Signature]] 的“承诺”操作(`Commitment`),将 |committed_messages| 数组输入包含 |holder_secret| 作为其唯一元素,以计算 |commitment_with_proof| 和 |secret_prover_blind|。|commitment_with_proof| 随其凭证请求一起发送给签发方,而 |holder_secret|、|prover_nym| 和 |secret_prover_blind| 则由持有方保留以备后用,并且从不披露。
  2. 签发方收到持有方的凭证请求(带有绑定化名,|featureOption| 等于 `"pseudonym"`),以及 |commitment_with_proof|。签发方使用本规范中的程序生成一个加密随机值作为 |signer_nym_entropy|,并使用 [[CFRG-Pseudonym-BBS-Signature]] 的“盲发行”操作生成基础证明。基础证明将包含 |signer_nym_entropy| 值。如果签发方需要重新向该持有方重新发行绑定到相同 |nym_secret| 的凭证,则应保留 |signer_nym_entropy| 值;否则,可以丢弃此值。
  3. 持有方在收到带有绑定化名的凭证后,使用本规范中的程序以及 [[CFRG-Pseudonym-BBS-Signature]] 的“验证和最终化”操作(`Verification and Finalization`),将 |committed_messages| 数组包含 |holder_secret| 作为其唯一元素,同时验证签名并计算 |nym_secret| 值。此操作使用 |holder_secret|、|prover_nym|、|signer_nym_entropy| 和 |secret_prover_blind| 等值。如果正在使用第三方监控,则需要将 |nym_secret| 值安全地共享给监控组织。
  4. 当持有方希望生成绑定到化名的派生证明时,他们需要确定 |nym_domain|。如前所述,这可能由验证方指定,也可能由持有方设置,具体取决于使用场景。然后,他们使用本规范中的程序以及 [[CFRG-Pseudonym-BBS-Signature]] 的“带化名的证明生成”操作(`Proof Generation with Pseudonym`)生成派生证明。此操作将 |nym_secret|、|nym_domain|、包含 |holder_secret| 作为其唯一元素的 |committed_messages| 数组,以及 |secret_prover_blind| 等作为输入。除了提供原始加密证明值外,它还返回包含在派生证明中的 |pseudonym| 值。
  5. 当验证方收到带有绑定化名的派生证明时,他们使用本规范中的程序以及 [[CFRG-Pseudonym-BBS-Signature]] 的“带化名的证明验证”操作(`Proof Verification with Pseudonym`)验证派生证明。请注意,这些程序还将验证指定的 |nym_domain| 是否用于计算 |pseudonym|。

可选功能摘要

本节总结了“基础”BBS 证明以及可选功能的输入、输出、证明序列化、任务和过程。所谓基础BBS,是指没有附加功能的 BBS 基础证明和派生证明。所有可选功能都是“附加的”,意味着在“基础”BBS 签名/证明的基础上生成了一些额外的输入、任务或输出。

表 1 发行方创建基础:输入等。
名称 任务 输入 签名算法
基础 BBS 基础:从 VC 生成 BBS 签名 基础:文档、证明选项、密钥材料、强制指针 BBS
匿名持有方绑定 基础 基础 + 来自持有方的带证明的承诺 盲 BBS
凭证绑定的化名 基础 + 生成 |signer_nym_entropy| 基础 + |signer_nym_entropy|,来自持有方的带证明的承诺 化名 BBS
持有方绑定和化名 基础 + 生成 |signer_nym_entropy| 基础 + |signer_nym_entropy|,来自持有方的带证明的承诺 化名 BBS
表 2 发行方创建基础:头部和序列化。
名称 证明头部字节 序列化输出
基础 BBS `0xd9`,`0x5d`,和 `0x02` 基础:bbsSignature,bbsHeader,publicKey,hmacKey 和 mandatoryPointers
匿名持有方绑定 `0xd9`,`0x5d`,和 `0x04` 基础
凭证绑定的化名 `0xd9`,`0x5d`,和 `0x06` 基础 + |signer_nym_entropy|
持有方绑定和化名 `0xd9`,`0x5d`,和 `0x08` 基础 + |signer_nym_entropy|
表 3 持有方添加派生:输入等。
名称 任务 输入 证明生成算法
基础 BBS 从 VC 和基础证明生成 BBS 派生证明 基础:从基础证明序列化中获取 bbsSignature,bbsHeader,publicKey,hmacKey 和 mandatoryPointers;选择性指针(持有方选择) BBS
匿名持有方绑定 基础 基础 + |holder_secret|,|prover_blind|(均为持有方已知) 盲 BBS
凭证绑定的化名 基础 + 计算 |nym_secret|,计算 |pseudonym| 基础 + |prover_nym|,|prover_blind|(均为持有方已知),|signer_nym_entropy|(由发行方包含在基础中),|nym_domain| 化名 BBS
持有方绑定和化名 基础 + 计算 |nym_secret|,计算 |pseudonym| 基础 + |holder_secret|,|prover_nym|,|prover_blind|(均为持有方已知),|signer_nym_entropy|(由发行方包含在基础中),|nym_domain| 化名 BBS
表 4 持有方添加派生:头部和序列化。
名称 证明头部字节 序列化输出
基础 BBS `0xd9`,`0x5d`,和 `0x03` 基础:bbsProof,compressedLabelMap,mandatoryIndexes,selectiveIndexes,presentationHeader
匿名持有方绑定 `0xd9`,`0x5d`,和 `0x05` 基础
凭证绑定的化名 `0xd9`,`0x5d`,和 `0x07` 基础 + |pseudonym|,|nym_domain|
持有方绑定和化名 `0xd9`,`0x5d`,和 `0x09` 基础 + |pseudonym|,|nym_domain|
表 5 验证派生:输入和算法。
名称 输入 证明验证算法
基础 BBS 基础:从派生证明序列化中获取 bbsProof,compressedLabelMap,mandatoryIndexes,selectiveIndexes,presentationHeader BBS
匿名持有方绑定 基础 盲 BBS
凭证绑定的化名 基础 + |pseudonym|(包含在派生证明中),|nym_domain| 化名 BBS
持有方绑定和化名 基础 + |pseudonym|(包含在派生证明中),|nym_domain| 化名 BBS

安全性考虑

在阅读本节之前,建议读者先熟悉 数据完整性规范的安全性考虑部分中提供的一般安全建议。

基础证明的安全属性

基础证明的安全性依赖于相关的BBS 签名的安全属性。数字签名可能具有许多理想的加密属性 [[Taming_EdDSAs]],其中包括:

EUF-CMA在选择消息攻击下的存在性不可伪造性)通常是签名方案所需的最低安全属性。它保证任何拥有签名者公钥的高效攻击者 p k 并接收任意数量的消息签名(以自适应方式选择消息): { m i , σ i } i = 1 N , 无法输出一个有效的签名 σ 用于一条新消息 m { m i } i = 1 N (除非概率极小)。如果攻击者对一条新消息输出了一个有效签名: ( m , σ ) , 则称之为存在性伪造

SUF-CMA在选择消息攻击下的强不可伪造性)是比EUF-CMA更强的概念。它保证任何拥有签名者公钥的高效攻击者 p k 并接收任意数量的消息签名: { m i , σ i } i = 1 N , 无法输出一个新的有效签名对 ( m , σ ) , 使得 ( m , σ ) { m i , σ i } i = 1 N (除非概率极小)。强不可伪造性意味着攻击者不仅无法对新消息签名,也无法对旧消息找到新的签名。

在 [[CDL2016]] 中,在一些合理的假设下,BBS 签名被证明是 EUF-CMA 的。此外,在 [[TZ2023]] 中,在类似假设下,BBS 签名被证明是 SUF-CMA 的。这两种情况下的假设都与离散对数问题的难度相关,而该问题在大规模量子计算条件下不被认为是安全的。

在非量子计算条件下,[[CFRG-BBS-SIGNATURE]] 为 BBS 签名套件的实现者提供了额外的安全指南。与配对友好曲线相关的进一步安全性考虑在 [[CFRG-PAIRING-FRIENDLY]] 中讨论。

派生证明的安全属性

派生证明的安全性依赖于相关的BBS 证明的安全属性。[[CDL2016]] 和 [[TZ2023]] 都证明了BBS 证明对 BBS 签名知识的零知识证明

如 [[CFRG-BBS-SIGNATURE]] 中所述,这意味着:

接收到证明的验证方无法确定用于生成该证明的签名,从而消除了常见的关联来源。通常,即使是从同一签名生成的两个证明,每个生成的证明也与随机值无法区分。

并且

该方案生成的证明向验证方证明生成证明的一方(持有方/证明方或其代理)拥有签名,但未透露签名本身。

更具体地说,验证BBS 证明需要原始签发方的公钥以及按正确顺序排列的未修改的、已披露的BBS 消息

隐私注意事项

选择性披露与数据泄漏

选择性披露允许持有方根据特定目的最小化验证方披露的信息。在设计支持选择性披露的整体系统时,必须注意尽量减少未计划向验证方披露的额外信息。这种泄漏可能通过系统的工件发生。这些工件可能来自系统的更高层(例如数据结构)或更低层的密码学原语。

例如,BBS签名方案是一种极其高效的方案,用于对多个消息生成签名,即发送给持有方的密码学签名的大小是固定的,与消息的数量无关。持有方随后可以选择性地向验证方披露这些消息中的任意部分,但作为加密方案的一部分,签发方签署的消息总数必须向验证方披露。如果需要避免此类信息泄漏,建议按照[[CFRG-BBS-SIGNATURE]]隐私注意事项部分的建议,将消息数量填充到一个通用长度。

在更高层次上,如何将数据映射到适合选择性披露的单个声明(即BBS消息)可能是数据泄漏的潜在来源。此加密套件能够通过使用JSON-LD处理将输入转换为RDF,消除许多可能泄漏信息的JSON数据结构工件(如嵌套、映射或数组位置等)。RDF可以被表达为规范化的、简单的主体-属性-值声明(在可验证凭证数据模型[[VC-DATA-MODEL-2.0]]中称为声明)。在以下内容中,我们将研究RDF规范化,这是一种将JSON-LD格式的可验证凭证映射为一组声明(BBS消息)的通用方案,用于选择性披露。我们将展示在执行此过程后,仍然存在可能的信息泄漏来源,并展示如何通过使用密钥伪随机函数(PRF)来缓解这种泄漏。

RDF规范化可用于将JSON-LD可验证凭证扁平化为一组声明。该算法依赖于可验证凭证的内容,并使用密码学哈希函数帮助对声明进行排序。本质上,这一过程是将JSON对象(表示JSON-LD文档中声明的主体)分配一个id(如果未定义`@id`字段)。这些id被称为空白节点id。这些id用于将声明表达为简单的主体-属性-值声明,以便可以区分每个声明中的主体。id值根据[[RDF-CANON]]的规范化算法以及文档中的数据和密码学哈希函数(如SHA-256)的输出确定。

以下展示了两组稍有不同的风帆可验证凭证及其规范化为一组可用于选择性披露的声明。通过更改6.1尺寸风帆的年份,我们可以看到这两组凭证之间的声明排序发生了重大变化。如果持有方仅披露其较大尺寸的风帆(7.0和7.8)的信息,验证方可能会发现风帆集合发生了变化,即信息泄漏。

      {
        "@context": [
          "https://www.w3.org/ns/credentials/v2",
          {
            "@vocab": "https://windsurf.grotto-networking.com/selective#"
          }
        ],
        "type": [
          "VerifiableCredential"
        ],
        "credentialSubject": {
          "sails": [
            {
              "size": 5.5,
              "sailName": "Kihei",
              "year": 2023
            },
            {
              "size": 6.1,
              "sailName": "Lahaina",
              "year": 2023 // 将更改此处以查看对规范化的影响
            },
            {
              "size": 7.0,
              "sailName": "Lahaina",
              "year": 2020
            },
            {
              "size": 7.8,
              "sailName": "Lahaina",
              "year": 2023
            }
          ]
        }
      }
              

上述可验证凭证的规范化形式。空白节点id的分配(即_:c14nX标签)依赖于可验证凭证的内容,这也会影响声明的排序。

      _:c14n0 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" .
      _:c14n0 <https://windsurf.grotto-networking.com/selective#size> "7.8E0"^^<http://www.w3.org/2001/XMLSchema#double> .
      _:c14n0 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
      _:c14n1 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n4 .
      _:c14n2 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" .
      _:c14n2 <https://windsurf.grotto-networking.com/selective#size> "7"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n2 <https://windsurf.grotto-networking.com/selective#year> "2020"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n3 <https://windsurf.grotto-networking.com/selective#sailName> "Kihei" .
      _:c14n3 <https://windsurf.grotto-networking.com/selective#size> "5.5E0"^^<http://www.w3.org/2001/XMLSchema#double> .
      _:c14n3 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n0 .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n2 .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n3 .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#sails> _:c14n5 .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#size> "6.1E0"^^<http://www.w3.org/2001/XMLSchema#double> .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> .
              

更新后的风帆集合,即6.1尺寸的风帆已更新为2024型号。这通过空白节点id的分配改变了声明的排序。

      {
        "@context": [
          "https://www.w3.org/ns/credentials/v2",
          {
            "@vocab": "https://windsurf.grotto-networking.com/selective#"
          }
        ],
        "type": [
          "VerifiableCredential"
        ],
        "credentialSubject": {
          "sails": [
            {
              "size": 5.5,
              "sailName": "Kihei",
              "year": 2023
            },
            {
              "size": 6.1,
              "sailName": "Lahaina",
              "year": 2024 // 新风帆以更新旧型号,改变了规范化
            },
            {
              "size": 7.0,
              "sailName": "Lahaina",
              "year": 2020
            },
            {
              "size": 7.8,
              "sailName": "Lahaina",
              "year": 2023
            }
          ]
        }
      }
              

上述可验证凭证的规范化形式。注意空白节点id分配和声明排序的差异。

      _:c14n0 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" .
      _:c14n0 <https://windsurf.grotto-networking.com/selective#size> "6.1E0"^^<http://www.w3.org/2001/XMLSchema#double> .
      _:c14n0 <https://windsurf.grotto-networking.com/selective#year> "2024"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n1 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" .
      _:c14n1 <https://windsurf.grotto-networking.com/selective#size> "7.8E0"^^<http://www.w3.org/2001/XMLSchema#double> .
      _:c14n1 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://www.w3.org/2018/credentials#VerifiableCredential> .
      _:c14n2 <https://www.w3.org/2018/credentials#credentialSubject> _:c14n5 .
      _:c14n3 <https://windsurf.grotto-networking.com/selective#sailName> "Lahaina" .
      _:c14n3 <https://windsurf.grotto-networking.com/selective#size> "7"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n3 <https://windsurf.grotto-networking.com/selective#year> "2020"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#sailName> "Kihei" .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#size> "5.5E0"^^<http://www.w3.org/2001/XMLSchema#double> .
      _:c14n4 <https://windsurf.grotto-networking.com/selective#year> "2023"^^<http://www.w3.org/2001/XMLSchema#integer> .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n0 .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n1 .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n3 .
      _:c14n5 <https://windsurf.grotto-networking.com/selective#sails> _:c14n4 .
              

为了防止这些空白节点id的分配及其对声明排序的影响导致的信息泄漏,会对空白节点id运行基于HMAC的伪随机函数(PRF)。HMAC密钥仅在签发方持有方之间共享,并且每个由签发方生成的基础证明都会使用一个新的HMAC密钥。可以在[[DI-ECDSA]]的规范化HMAC测试向量中看到此示例。 如下一节所述,为了使BBS保持不可链接性,我们不使用基于HMAC的空白节点id,而是基于HMAC生成打乱版本的排序,如测试向量所示。请注意,与ECDSA-SD方法相比,这种方法在空白节点id方面提供的信息隐藏较少,因为空白节点id的数量可能会泄漏,但通过对空白节点id应用HMAC生成的本质上唯一的标识符,可以防止链接攻击。

选择性披露与不可链接性

在某些可验证凭证(VC)的使用场景中,为了保护持有方的隐私,防止多个不同验证方交互的跟踪或关联可能非常重要。特别是,我们考虑两种重要情况:(i) 验证方与签发方串通,以及 (ii) 验证方与验证方串通。在第一种情况下,如所示,验证方向凭证的原始签发方报告与持有方的交互。在这种情况下,签发方可以通过已签发的VC跟踪持有方与各种验证方的所有交互。在第二种情况下,如所示,多个验证方串通共享他们与持有方交互的信息。


      图示显示多个验证方将数据发送回签发方。
      图表从上到下布局,顶部是一个标记为签发方的圆圈,连接到下方标记为持有方的圆圈。从标记为持有方的圆圈有多个箭头指向其他标记为验证方的圆圈。从标记为验证方的圆圈有虚线箭头返回到标记为签发方的圆圈,显示串通的数据流。
验证方与签发方串通。

      图示显示多个验证方彼此共享信息。
      图表从上到下布局,顶部是一个标记为签发方的圆圈,连接到下方标记为持有方的圆圈。从标记为持有方的圆圈有多个箭头指向其他标记为验证方的圆圈。从标记为验证方的圆圈有虚线箭头返回到其他标记为签发方的圆圈,显示验证方之间串通的数据流。
验证方与验证方串通。

我们使用术语不可链接性来描述VC系统防止此类“关联攻击”对持有方隐私的能力。尽管“不可链接性”这一术语相对较新,但[[NISTIR8053]]的第3.3节讨论并提供了一个关于通过关联攻击重新识别的案例研究。关于数据隐私关联攻击的知识系统化可以在[[Powar2023]]中找到。最广泛使用的用户隐私关联攻击发生在网络浏览器指纹识别的实践中,其调查可以在[[Pugliese2020]]中找到。

为了量化关联的概念,[[Powar2023]]引入了匿名集的概念。在我们关心的VC场景中,匿名集将包含特定VC的持有方以及与特定签发方相关的其他持有方。匿名集越小,持有方越可能被验证方跟踪。由于签名的VC包含对签发方公钥的引用,对于持有特定签发方VC的持有方来说,匿名集的初始大小是该签发方使用特定公/私钥对签发的VC数量。非恶意的签发方应尽量减少用于签发VC的公/私钥对的数量。请注意,匿名集的概念类似于[[vc-bitstring-status-list]]中的群体隐私概念。当我们在此使用“关联”一词时,通常是指任何导致匿名集大小减少的机制。

支持选择性披露的VC系统中的关联来源:

  1. 密码学原语的工件。
  2. 将VC映射为适合选择性披露的一组声明的工件。
  3. VC中证明选项和强制披露信息的工件。
  4. VC中选择性披露的信息。
  5. 基于外部VC系统的关联。

我们将在下文中讨论这些内容。

通过密码学工件的关联

密码学哈希、HMAC和数字签名本质上会生成高度唯一的标识符。诸如SHA-256之类的哈希函数的输出,由于其抗碰撞特性,保证在不同输入下本质上是唯一的,从而导致强关联,即将匿名集大小减少为1。同样,诸如Ed25519和确定性ECDSA之类的确定性签名算法会为不同输入生成本质上唯一的输出,并导致强关联。

这意味着持有方可以通过VC中的数字签名、HMAC或哈希工件轻松地在验证方之间被跟踪,因此容易受到验证方-验证方串通和验证方-签发方串通的攻击。某些形式的ECDSA等随机化签名算法可以允许签发方为相同输入生成许多不同的签名,并将这些签名发送给持有方以供不同的验证方使用。这种方法可以用来防止基于验证方-验证方串通的跟踪,但无法防止验证方-签发方串通。

要实现不可链接性,需要专门设计的密码学签名方案,允许持有方生成所谓的签名知识的零知识证明(ZKPKS)。这意味着持有方可以在此类方案中从签发方获取签名,计算一个ZKPKS并将其发送给验证方。此ZKPKS无法链接回原始签名,但具有签名的所有理想属性,即验证方可以使用它来验证消息是否由签发方的公钥签名,以及消息是否未被篡改。此外,持有方可以为不同的验证方生成任意数量的ZKPKS,这些ZKPKS本质上是独立且不可链接的。BBS是一种支持此功能的签名方案。

尽管文档中称为BBS证明的ZKPKS具有保证的不可链接性属性,但BBS在与选择性披露一起使用时有两个工件可能导致关联。这些工件是最初签名的消息总数和披露声明的索引值。有关讨论和缓解技术,请参阅[[CFRG-BBS-SIGNATURE]]中的隐私注意事项。

如[[CFRG-BBS-SIGNATURE]]的签发方的公钥部分所述,存在一种潜在威胁,即签发方可能使用多个公钥,其中一些用于通过验证方-签发方串通跟踪特定用户子集。由于签发方的公钥必须对验证方可见,即它在BBS证明(派生证明)中被引用,如果签发方有许多不同的公钥,特别是如果它对一小部分用户(持有方)使用这些公钥的子集,这可能被用作关联点。

通过VC处理的关联

我们在信息泄漏部分看到,RDF规范化使用哈希函数对声明进行排序,并基于HMAC对声明的顺序进行进一步的打乱。这可能会留下指纹,从而允许某种程度的关联。关联的强度取决于VC中空白节点(本质上是JSON对象)的数量以及披露的索引数量。给定n个空白节点和k个披露的索引,在最坏情况下,这将导致匿名集大小减少一个因子C(n, k),即从n个元素的集合中选择大小为k的组合数。通过减少VC中的空白节点数量,例如保持VC简短和简单,可以将此数字保持在较低水平。

通过JSON-LD节点标识符的关联

JSON-LD是一种基于JSON的格式,用于序列化关联数据。因此,它支持为文档中的每个对象(在JSON-LD术语中称为“节点”)分配一个全局唯一的`@id`属性(节点标识符)。这允许关联数据的链接,从而使关于同一实体的信息可以被关联。这种关联可能是可取的,也可能是不可取的,具体取决于使用场景。

在使用BBS的不可链接性功能时,不能为个人或其个人身份信息使用全局唯一的节点标识符,因为它们提供的强关联是不可取的。请注意,当表达关于非个人信息的声明时(例如,使用全局唯一标识符来标识一个大国或一场音乐会活动),使用此类标识符是可以接受的。另外请注意,JSON-LD使用的`@context`,将术语映射到IRI,通常不会影响不可链接性。

通过证明选项和强制披露的关联

在[[vc-data-integrity]]规范中,给出了VC的`proof`属性的许多属性。需要注意的是,可选字段不应在验证方之间提供强关联。这些可选字段包括:idcreatedexpiresdomainchallengenonce。例如,可选的created字段是一个`dateTimeStamp`对象,可以指定证明的创建日期,精确到任意的亚秒级粒度。如果存在此类信息,可能会大大减少匿名集的大小。如果签发方希望包含此类信息,则应尽可能使其粒度较粗,相对于一段时间内签发的VC数量。

签发方还可以通过在创建基础证明时使用的`mandatoryPointers`输入,强制持有方验证方披露某些声明。请参阅部分。通过强制,我们指的是生成的派生证明在未向验证方披露这些声明时将无法验证。应注意,如果要求披露此类信息,匿名集应保持足够大。

通过持有方选择性披露的关联

如[[Powar2023]]所述,有许多关于通过关联攻击重新识别个人的案例。因此,建议持有方尽可能少地披露信息,以帮助保持匿名集的大小。此外,已经多次证明,看似无害的信息可能具有高度的唯一性,从而导致重新识别或跟踪。请参阅[[NISTIR8053]],了解关于马萨诸塞州前州长的一个特别著名案例的详细说明,以及[[Powar2023]]中对94个此类公开案例的进一步分析和分类。

通过外部VC系统的关联

需要指出的是,保持不可链接性(即匿名性)需要在持有和传输VC的系统中小心处理。网络工件(如IP地址(第3层)或以太网/MAC地址(第2层))是众所周知的关联来源。例如,如果移动电话的MAC地址在重新访问特定接入点时被使用,这可能会导致用户被跟踪,这促使移动电话制造商提供了MAC地址随机化功能。公共IP地址通常提供足够的信息,可以将个人定位到一个城市或国家内的区域,从而可能大大减少匿名集的大小。

测试向量

基础基本示例

文档测试向量基于一个完全虚构的永久居民卡,并分为两组——由签发方生成的(“基础证明”)和由持有方生成的(“派生证明”)。

基础证明

要向文档添加选择性披露的基础证明,签发方需要以下加密密钥材料:

  1. 签发方的私钥/公钥对,即将成为证明的一部分的验证方法所对应的密钥对。
  2. 一个 HMAC 密钥。此密钥用于随机化空白节点 ID 的顺序,以避免通过空白节点 ID 排序可能导致的信息泄漏。此密钥仅使用一次,并在签发方和持有方之间共享。在这种情况下,HMAC 作为伪随机函数(PRF)使用。

用于生成测试向量以测试添加基础证明的密钥材料如下所示。BBS 密钥对和 HMAC 密钥使用十六进制表示。

          

在我们的场景中,将签发永久居民凭证。未签名的永久居民文档如下所示。


          

此强制性信息通过一个 JSON 指针数组指定,如下所示。


          

将上述 JSON 指针应用于文档的结果如下所示。


          

未签名文档的转换从文档规范化开始,如下所示。


          

为了防止通过空白节点 ID 的排序可能导致的信息泄漏,这些 ID 通过 PRF(即 HMAC)处理,生成如下所示的规范化 HMAC 文档。这表示将根据披露要求分组的声明的有序列表,这些声明在分组后仍将按此列表中的顺序排列。


          

上述规范化文档中的列表被分为强制性和非强制性声明。选择性披露转换过程的最终输出如下所示。请注意,这些声明现在被分组为强制性或非强制性披露,并且记住了每个声明在前一列表中的索引。


          

下一步是创建基础证明配置并对其进行规范化。以下是两个示例。


          

          

在哈希步骤中,我们计算规范化证明选项的 SHA-256 哈希以生成 `proofHash`,并计算所有强制性 N-Quads 的 `JOIN` 的 SHA-256 哈希以生成 `mandatoryHash`。以下以十六进制格式显示。


          

下面显示了以十六进制表示的计算出的 `bbsSignature` 和 `mandatoryPointers`。这些被作为最终序列化步骤的输入,与 `hmacKey` 一起使用。


          

最后,将上述值通过第 节的算法处理,生成 `proofValue`,并将其用于签名的基础文档,如下所示。


        
派生证明

随机数被使用,并且可选的 `presentationHeader` 可以作为附加输入,用于创建 BBS 证明。为了提供一组确定性的测试向量,我们使用了 [[CFRG-BBS-SIGNATURE]] 中的 模拟随机标量 程序。我们用于生成派生证明测试向量的 `seed` 和 `presentationHeader` 值如下所示(以十六进制表示)。


          

要创建派生证明,持有方从包含基础证明的签名文档开始。我们将用于这些测试向量的基础文档是上述第 节中的最终示例。第一步是运行第 节的算法以恢复 `bbsSignature`、`hmacKey` 和 `mandatoryPointers`,如下所示。


          

接下来,持有方需要指明是否希望向验证方披露任何非强制性声明,通过指定选择性披露的 JSON 指针。这些如下所示。


          

为了生成 `revealDocument`(即最终将被签名并发送给验证方的未签名文档),我们将选择性指针附加到强制性指针,并将这些组合指针与不包含证明的文档一起输入到 [[DI-ECDSA]] 的 `selectJsonLd` 算法中。结果如下所示。


          

现在我们知道披露文档的样子了,我们需要向验证方提供适当更新的信息,说明哪些声明是强制性的,以及所选非强制性声明的索引。运行第 节的第 6 步会生成关于原始文档中各种声明组的大量信息。以下显示了这些组的索引部分。


          

验证方需要能够聚合和哈希强制性声明。为此,我们向他们提供了强制性声明的索引列表,这些索引相对于披露文档中的位置进行了调整(即相对于 `combinedIndexes`),而 `selectiveIndexes` 则相对于它们在 `nonMandatoryIndexes` 中的位置进行了调整。这些“调整后”的索引如下所示。


          

最后一个重要的披露数据是 `labelMap`,它是规范化空白节点 ID 到基于 HMAC 的随机化 ID 的映射,根据第 节计算。以下显示了此映射以及其余的披露数据(不包括披露文档)。


          

最后,使用上述披露数据和第 节的算法,我们获得了如下所示的签名派生(披露)文档。


        

基线增强示例

展示选择性披露功能,包括强制披露、选择性披露以及两者的重叠,要求输入的凭证文档比之前的测试向量包含更多内容。为了避免测试向量过长,起始文档测试向量基于一个完全虚构的风帆(帆船)比赛场景。此外,我们将测试向量分为两组,一组由签发方生成(基础证明),另一组由持有方生成(派生证明)。

基础证明

要向文档添加选择性披露的基础证明,签发方需要以下加密密钥材料:

  1. 签发方的私钥/公钥对,即将成为证明一部分的验证方法所对应的密钥对。
  2. 一个 HMAC 密钥。此密钥用于随机化空白节点 ID 的顺序,以避免通过空白节点 ID 排序可能导致的信息泄漏。此密钥仅使用一次,并在签发方和持有方之间共享。在这种情况下,HMAC 作为伪随机函数(PRF)使用。

用于生成测试向量以测试添加基础证明的密钥材料如下所示。BBS 密钥对和 HMAC 密钥使用十六进制表示。

          

在我们的场景中,一名水手正在向比赛组织者注册参加将在毛伊岛举行的多日风帆比赛系列。组织者将检查水手的设备以确认所声明的内容是否准确。水手的未签名设备清单如下所示。


          

除了让其他水手了解他们的竞争对手可能使用的设备类型外,每名水手还必须披露其最近的风帆板的年份以及两块帆的完整详细信息。请注意,所有水手都通过印在其所有设备上的帆号进行标识。此强制性信息通过一个 JSON 指针数组指定,如下所示。


          

将上述 JSON 指针应用于水手的设备文档的结果如下所示。


          

未签名文档的转换从文档规范化开始,如下所示。


          

为了防止通过空白节点 ID 的排序可能导致的信息泄漏,这些 ID 通过 PRF(即 HMAC)处理,生成如下所示的规范化 HMAC 文档。这表示将根据披露要求分组的声明的有序列表,这些声明在分组后仍将按此列表中的顺序排列。


          

上述规范化文档中的列表被分为强制性和非强制性声明。选择性披露转换过程的最终输出如下所示。请注意,这些声明现在被分组为强制性或非强制性披露,并且记住了每个声明在前一列表中的索引。


          

下一步是创建基础证明配置并对其进行规范化。以下是两个示例。


          

          

在哈希步骤中,我们计算规范化证明选项的 SHA-256 哈希以生成 `proofHash`,并计算所有强制性 N-Quads 的 `JOIN` 的 SHA-256 哈希以生成 `mandatoryHash`。以下以十六进制格式显示。


          

下面显示了以十六进制表示的计算出的 `bbsSignature` 和 `mandatoryPointers`。这些被作为最终序列化步骤的输入,与 `hmacKey` 一起使用。


          

最后,将上述值通过第 节的算法处理,生成 `proofValue`,并将其用于签名的基础文档,如下所示。


        

匿名持有者绑定功能

持有者绑定承诺生成

使用匿名持有者绑定功能的第一步是持有者生成其|holderSecret|值,然后根据[[CFRG-Blind-BBS-Signature]]的承诺计算过程计算一个带有证明的承诺。以下是此过程的示例值和输出。


                  

                  

|holderSecret|和|secretProverBlind|应由持有者保留并保密。|commitmentWithProof|值应传递给签发方。

持有者绑定基础证明

在匿名持有者绑定选项下添加基础证明的过程从签发方接收持有者的|commitmentWithProof|值并使用[[CFRG-Blind-BBS-Signature]]的承诺验证过程验证该值开始。 第基础证明部分中解释和使用的加密密钥材料也将在此处使用,并在下方重复。

                  

在此场景中,我们考虑电子版的驾驶执照。


                  

为了保护持有者的隐私,唯一的强制性字段是“issuer”和“expirationDate”,如以下强制性指针所示。



                  

未签名文档的转换从文档规范化开始,如下所示。


                  

为了防止空白节点 ID 的排序可能导致的信息泄漏,这些 ID 通过 PRF(即 HMAC)处理,生成如下所示的规范化 HMAC 文档。这表示将根据披露要求分组的声明的有序列表,这些声明在分组后仍将按此列表中的顺序排列。


                  

上述规范化文档被分为强制性和非强制性声明。选择性披露转换过程的最终输出如下所示。每个声明现在被分组为强制性或非强制性,并记住了其在前一列表中的索引。


                  

下一步是创建基础证明配置并对其进行规范化。以下是两个示例。


                  

                  

在哈希步骤中,我们计算规范化证明选项的 SHA-256 哈希以生成|proofHash|,并计算所有强制性 N-Quads 的连接的 SHA-256 哈希以生成`mandatoryHash`。以下以十六进制格式显示。


                  

现在我们使用[[CFRG-Blind-BBS-Signature]]的盲签名生成过程,在 过程中。 以下显示了计算出的|bbsSignature|、|bbsHeader|、|publicKey|、 |hmacKey|、|mandatoryPointers|和|featureOption|,其中字节数据以十六进制显示。


                  

最后,将上述值通过第 节的算法处理,生成|proofValue|,并将其用于签名的基础文档,如下所示。


                  
持有者绑定派生证明

如第节所述,我们使用模拟的随机数生成过程并演示了|presentationHeader|的使用。这里使用了相同的|seed|和|presentationHeader|,并在下方重复。


                    

为了创建派生证明,持有者从包含基础证明的签名文档开始。我们将用于这些测试向量的基础文档是上述第节的最终示例。 第一步是运行第节的算法以 恢复|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey|、 |mandatoryPointers|和|featureOption|,如下所示。


                    

接下来,持有者需要指明他们希望向验证方披露的其他内容(如果有),通过指定选择性披露的 JSON 指针。在此情况下,持有者仅希望披露其驾驶权限。


                    

为了生成`revealDocument`(即最终将签名并发送给验证方的未签名文档),我们将选择性指针附加到强制性指针,并将这些组合指针与不包含证明的文档一起输入到[[DI-ECDSA]]的`selectJsonLd`算法中,得到如下结果。


                    

现在我们知道披露文档的样子了,我们需要向验证方提供适当更新的信息,说明哪些声明是强制性的,以及所选非强制性声明的索引。运行第 节的第 6 步会生成关于相对于原始文档的各种声明组的大量信息。下方显示了这些组的索引部分。


                    

验证方需要能够聚合和哈希强制性声明。为了实现这一点,我们向他们提供了强制性声明的索引列表,这些索引相对于披露文档中的位置进行了调整(即相对于`combinedIndexes`),而`selectiveIndexes`需要相对于`nonMandatoryIndexes`中的位置进行调整。这些“调整后”的索引如下所示。



                    

披露数据的最后一个重要部分是规范化空白节点 ID 到基于 HMAC 的打乱 ID 的映射,即`labelMap`,根据第 节计算。下方显示了此映射以及披露数据的其余部分(不包括披露文档)。请注意,这里显示的结果适用于|featureOption|等于`"anonymous_holder_binding"`的情况,该选项使用[[CFRG-Blind-BBS-Signature]]的盲证明生成过程。请注意,|blindAdjDisclosedIdxs|是证明序列化过程中使用的最终 BBS 选择性索引集,来自盲 BBS 证明生成函数,该函数以|adjSelectiveIndexes|作为输入。


                    

最后,使用上述披露数据和第 节的算法,我们获得了如下所示的签名派生(披露)文档。


                  

凭证绑定的化名功能

证明者化名承诺生成

使用凭证绑定的化名功能的第一步是持有者生成其秘密值|prover_nym|,然后根据[[CFRG-Pseudonym-BBS-Signature]]的“承诺”操作计算一个带有证明的承诺。以下是此过程的示例值和输出。


            

            

|prover_nym|和|secretProverBlind|应由持有者保留并保密。|commitmentWithProof|值应传递给签发方。

化名基础证明

在化名功能选项下添加基础证明的过程从签发方接收持有者的|commitmentWithProof|值并生成一个加密随机值|signer_nym_entropy|开始。


            

本示例将使用与中显示的相同密钥材料,与中显示的相同未签名文档,以及与中显示的相同强制性指针。这将生成与中显示的相同规范化文档,与中显示的相同规范化 HMAC 文档,以及与中显示的相同“添加基础转换”。

本示例使用与中相同的证明配置。这将生成与中相同的规范化基础证明。结合上述假设,将生成与中相同的基础哈希。

由于|featureOption|等于`"pseudonym"`,第节的过程将生成如下所示的输出。这使用了[[CFRG-Pseudonym-BBS-Signature]]的签名生成算法。请注意包含|signer_nym_entropy|和|featureOption|值,这些值需要传递给持有者。


            

最后,将上述值通过第节的算法处理,生成`proofValue`,并将其用于签名的基础文档,如下所示。


          
化名派生证明

如第节所述,我们使用模拟的随机数生成过程来演示|presentationHeader|的使用。这里使用了与中给出的相同|seed|和|presentationHeader|。

为了创建派生证明,持有者从包含基础证明的签名文档开始。我们将用于这些测试向量的基础文档是上述中的最终示例。第一步是运行第节的算法以恢复|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey|、|mandatoryPointers|、|signer_nym_entropy|和|featureOption|,如下所示。


            

接下来,持有者使用[[CFRG-Pseudonym-BBS-Signature]]的“验证和最终化”操作来验证签名并计算|nym_secret|值。此操作使用|prover_nym|、|signer_nym_entropy|和|secret_prover_blind|值等。


            

接下来,持有者需要指明他们希望向验证方披露的非强制性声明(如果有),通过指定选择性披露的 JSON 指针。在此情况下,持有者披露了与中给出的相同信息。这将生成与中显示的相同|revealDocument|。

运行会生成与中显示的相同派生组索引信息,以及与中显示的相同调整后的强制性和选择性索引。

中,我们基于中显示的相同|verfifier_id|计算|pseudonym|。的最终输出如下所示。请注意包含|featureOption|和计算的|pseudonym|值。


            

最后,使用上述披露数据和第节的算法,我们获得了如下所示的签名派生(披露)文档。


          

持有者绑定和化名功能

持有者秘密和证明者化名承诺生成

使用持有者绑定和化名功能的第一步是持有者生成其|holder_secret|和|prover_nym|值, 然后根据[[CFRG-Pseudonym-BBS-Signature]]的“承诺”操作计算一个带有证明的承诺。以下是此过程的示例值和输出。


                    

                    

                    

|holder_secret|、|prover_nym|和|secretProverBlind|需要由持有者保留并保密。|commitmentWithProof|值需要传递给签发方。

持有者绑定和化名基础证明

在化名功能选项下添加基础证明的过程从签发方接收持有者的|commitmentWithProof|值并生成一个加密随机值|signer_nym_entropy|开始。


                    

此示例将使用与 中显示的相同密钥材料, 以及与中显示的相同未签名文档, 以及与中显示的相同强制性指针。 这将生成与中显示的相同规范文档, 与中显示的相同规范HMAC文档, 以及与中显示的相同“添加基础转换”。

此示例使用与中相同的证明配置。 这将生成与中相同的规范基础证明。 结合上述假设,生成与中相同的基础哈希。

由于|featureOption|等于`"holder_binding_pseudonym"`,第 节的过程将生成如下所示的输出。 这使用了[[CFRG-Pseudonym-BBS-Signature]]的签名生成算法。请注意包含|signer_nym_entropy|和|featureOption|值, 因为这些需要传递给持有者。


                  

最后,上述值通过第节的算法处理,生成`proofValue`, 并用于如下所示的签名基础文档。


                  
持有者绑定和化名派生证明

如第节所述,我们使用模拟的随机数生成过程并演示了|presentationHeader|的使用。 这里使用了与中给出的相同|seed|和|presentationHeader|。

为了创建派生证明,持有者从包含基础证明的签名文档开始。 我们将用于这些测试向量的基础文档是上述中的最终示例。 第一步是运行第节的算法以恢复|bbsSignature|、|bbsHeader|、|publicKey|、|hmacKey|、 |mandatoryPointers|、|signer_nym_entropy|和|featureOption|,如下所示。


                  

接下来,持有者使用[[CFRG-Pseudonym-BBS-Signature]]的“验证和最终化”操作来验证签名并计算|nym_secret|值。 此操作使用|holder_secret|、|prover_nym|、|signer_nym_entropy|和|secret_prover_blind|值等。


                  

接下来,持有者需要指明他们希望向验证方披露的非强制性声明(如果有),通过指定选择性披露的JSON指针。 在此情况下,持有者披露了与中给出的相同信息。 这将生成与中显示的相同|revealDocument|。

运行会生成与中显示的相同派生组索引信息, 以及与中显示的相同调整后的强制性和选择性索引。

中,我们基于中显示的相同|verfifier_id|计算|pseudonym|。 的最终输出如下所示。请注意包含|featureOption|和计算的|pseudonym|值。


                  

最后,使用上述披露数据和第节的算法,我们获得了如下所示的签名派生(披露)文档。


                  

致谢

本规范的工作得到了“重启信任网络”社区的支持,该社区由 Christopher Allen、Shannon Appelcline、Kiara Robles、Brian Weller、Betty Dhamers、Kaliya Young、Manu Sporny、Drummond Reed、Joe Andrieu、Heather Vescent、Kim Hamilton Duffy、Samantha Chase、Andrew Hughes、Erica Connell、Shigeya Suzuki 和 Zaïda Rivai 组织。由 Phil Windley、Kaliya Young、Doc Searls 和 Heidi Nobantu Saul 主持的互联网身份研讨会的参与者也通过多次工作会议支持了本规范的改进,这些会议旨在教育、讨论和改进本规范。

工作组还感谢我们的主席 Brent Zundel、前主席 Kristina Yasuda,以及 W3C 工作人员联络人 Ivan Herman,他们在 W3C 标准化过程中提供了专业管理和稳定指导。

本规范的部分工作得到了美国国土安全部科学与技术局的资助,合同号为 70RSAT20T00000003、70RSAT20T00000029、70RSAT20T00000033、70RSAT21T00000016、70RSAT23T00000005、70RSAT20T00000010/P00001、70RSAT20T00000029、70RSAT21T00000016/P00001、70RSAT23T00000005、70RSAT23C00000030、70RSAT23R00000006、70RSAT24T00000011,以及国家科学基金会的资助(NSF 22-572)。本规范的内容不一定反映美国政府的立场或政策,不应推断为官方认可。

工作组还感谢以下个人对本规范的审阅和反馈(按字母顺序排列):

Will Abramson, Mahmoud Alkhraishi, Christopher Allen, Joe Andrieu, Bohdan Andriyiv, Anthony, George Aristy, Hadley Beeman, Greg Bernstein, Bob420, Sarven Capadisli, Melvin Carvalho, David Chadwick, Matt Collier, Gabe Cohen, Sebastian Crane, Kyle Den Hartog, Veikko Eeva, Eric Elliott, Raphael Flechtner, Julien Fraichot, Benjamin Goering, Kim Hamilton Duffy, Joseph Heenan, Helge, Ivan Herman, Michael Herman, Anil John, Andrew Jones, Michael B. Jones, Rieks Joosten, Gregory K, Gregg Kellogg, Filip Kolarik, David I. Lehn, Charles E. Lehner, Christine Lemmer-Webber, Eric Lim, Dave Longley, Tobias Looker, Jer Miller, nightpool, Luis Osta, Nate Otto, George J. Padayatti, Addison Phillips, Mike Prorock, Brian Richter, Anders Rundgren, Eugeniu Rusu, Markus Sabadello, silverpill, Wesley Smith, Manu Sporny, Patrick St-Louis, Orie Steele, Henry Story, Oliver Terbu, Ted Thibodeau Jr, John Toohey, Bert Van Nuffelen, Mike Varley, Snorre Lothar von Gohren Edwin, Jeffrey Yasskin, Kristina Yasuda, Benjamin Young, Dmitri Zagidulin, and Brent Zundel.