去中心化数字身份DID简介——四、用户属性的零知识证明

上一篇文章中,我们介绍了用户具有多个身份属性时,选择性的把其中的一个属性暴露出来,而不会造成其他信息的暴露。更进一步的情况,某些时候我们只需要验证用户的年龄达到多少岁,或者小于多少岁,但是并不关心用户的具体年龄和出生日期,比如在购买烟酒时,商家需要验证用户的年龄大于18岁。除了年龄,住址、民族等都可能会有对某个断言进行验证的情况。比如某旅游景点,对本市所有居民免费,所以居民只需要证明自己身份证上的住址在某市,而不需要暴露具体的居住地址。这些只给出证明的答案,而不暴露其他任何身份信息的情况,都是零知识证明的范畴。

传统的零知识证明算法很复杂,难以理解,也难以实现,而且就算实现了,也不能很好的满足我们数字身份中关于身份属性验证的问题,因为这里涉及到三方:发证方、持证方、验证方。在发证方将证件(可验证声明VC)发给持证方时,发证方并不知道持证方以后会遇到验证大于18岁,还是验证大于65岁,另外持证方在生成亮证(可验证表达VP)时,只需要持证方和验证方进行交互,不应该在此时引入发证方。所以我们可以认为:

1.生成VC和生成VP是两个独立的事件,生成VP时不应该有发证方参与。

2.验证方信任的是发证方,而不是持证方,所以持证方只是简单的证明自己大于18岁,但是这个证明没有发证方的背书,是不可信的。

基于以上条件,本文提出了一种身份证明的零知识证明方法,该方法将VC和VP独立,生成VP时发证方不需要参与,而且VP中给出的证明具有零知识性,而且有发证方背书。

0x0. Issuer:根据采样粒度与采样范围进行数据的断言构建

发证方Issuer要对某个属性做出证明,首先需要在该数据所在的作用域进行采样,采样包括采样的粒度和范围。以用户的生日属性为例,其作用范围虽然可以是历史上任意一天,但是我们考虑实际情况,可以将采样范围定义在1900-1-1到2020-1-1,然后是采样粒度的问题,如果我们以年为粒度,也就是说我们只关心用户出生的那个年份来确定年龄,如果我们以年月粒度,那么就可以根据具体出生在几月来确定年龄,最细的粒度就是到天。这里简单起见,我们就以年为采用粒度,这样我们就建立了一个从1900到2020的数组:

[1900,1901,1902,…,2019,2020]

然后我们还可以增加下区间”<1900”和上区间”>2020”两个元素,从而覆盖年份的所有取值范围。

我们有了年份采样的数组,接下来是根据用户的实际情况,为每个元素增加断言,这里我以当年用户是否已经出生为断言,所以我们的数组变为,以小明1985年出生为例:

[<1900未出生, 1900未出生,1901未出生,1902未出生,…1984未出生,1985已出生,1986已出生,…,2019已出生,2020已出生,>2020已出生]

有了这么一个断言数组,我们可以简化断言为更简洁一些的形式:

Min=1900,Max=2020,Step=1,OtherRange=Both,Assert=[0,0,0,0,……,0,1,1,1,…,1,1],Format=“{0}:{1}"

这里定义了数组的范围,采样粒度,边界处理,以及断言的结果。Format是定义了断言字符串的格式。

0x1. Issuer:断言默克尔树的构建

现在我们已经构建好了断言数组,接下来就只需要将断言数组作为默克尔树的叶子节点,并采用上一篇文章中说的加盐方法,防止哈希碰撞,从而构建一个加盐断言默克尔树。

UntitledImage

0x2. Issuer:默克尔根签名,VC生成

这棵树构建好了,得到了默克尔根,发证方接下来使用自己的私钥对这个默克尔根进行签名,并将签名、默克尔树生成办法、随机种子等信息放到VC中,以供用户认证。以下是公安部门针对用户生成的身份证VC,并在其中包含了出生年份的断言。

{
  // VC内容所遵循的JSON-LD标准
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://studyzyexamples.com/identity/v1"
  ],
  // 本VC的唯一标识,也就是证书ID
  "id": "vc511112200001010015",
  // VC内容的格式
  "type": ["VerifiableCredential", "Identity"],
  // 本VC的发行人
  "issuer": "did:公安部门ID",
  // 本VC的发行时间
  "issuanceDate": "2010-07-01T19:73:24Z",
  // VC声明的具体内容
  "credentialSubject": {
    // 被声明的人的DID
    "id": "did:cid:511112200001010015",
    // 声明内容:姓名、性别、生日、民族、住址等
    "name":"小明",
    "gender":"男",
    "birthdate":"2000-01-01",
    "nation":"汉",
    "address":"A省B市C区D街道xxx号",
    //接下来是种子数、默克尔根、公安的签名
    "seed":"23523865082340324",
    "merkleRoot":"ea59a369466be42d1a4783f09ae0721a5a157d6dba9c4b053d407b5a4b9af145",
    "rootSignature":"3066022051757c2de7032a0c887c3fcef02ca3812fede7ca748254771b9513d8e266",
    "signer":"did:公安部门ID#keys-1"
    //接下来是对出生年份断言默克尔树的构建和签名
    "birthYearAssert":{
      "min":1900,
      "max":2020,
      "step":1,
      "otherRange":"Both",
      "assert":[0,0,0,0,0,0,......0,1,1,1,1,1.......1],
      "format":"{0}:{1}",
      "seed":"9013492332268116070",
      "merkleRoot":"806de4a868682738bb328a4801c09d88a93ce1301e3dbff08f5b0881be01fddb",
      "rootSignature":"3077022051757c2de7032a0c887c3fcef02ca3812fede7ca748254771b9513d8e255",
      "signer":"did:公安部门ID#keys-1"
    }
  },
  // 对本VC的证明
  "proof": {
    "creator": "did:公安部门ID#keys-1",
    "type": "Secp256k1",
    "signatureValue": "3044022051757c2de7032a0c887c3fcef02ca3812fede7ca748254771b9513d8e2bb"
  }
}

0x3. Verifier:生成断言请求

现在卖烟酒的商家Verifier要求顾客证明自己大于18岁,换句话说,以当前2020年来说,就是要证明18年前 2002年已经出生。所以商家需要顾客证明的断言是:

2002:1

商家将这个断言生成断言请求,并发送给顾客的数字身份APP中,比如商家可以把断言请求生成二维码,让所有顾客都扫码,生成VP。

0x4. Holder:生成零知识证明VP

现在顾客Holder已经得知了Verifier的断言请求,于是根据断言请求,找到该断言在断言默克尔树中的位置,并形成:断言内容、断言位置、默克尔验证路径、Salt、默克尔根、公安机关DID和签名的验证判断所需的全部元素,而这一切都是基于之前公安机关颁发给用户的VC生成的,并不需要联网,更不需要公安机关在本次验证过程中的参与。

{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://studyzyexamples.com/identity/v1"
  ],
  "type": "VerifiablePresentation",
  // 本VP包含的VC的内容
  "verifiableCredential": [{
    "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://studyzyexamples.com/identity/v1"
  ],
  "id": "vc511112200001010015",
  "type": ["VerifiableCredential", "Identity"],
  "issuer": "did:公安部门ID",
  "issuanceDate": "2010-07-01T19:73:24Z",
  "credentialSubject": {
    "id": "did:cid:511112200001010015",
    //以下是断言的内容,意思是2002年已经出生
    "assert":"2002:1",
    //以下是验证披露字段有效性的数据
    //数据在默克尔树中的索引
    "dataIndex":103,
    //本数据加盐的值
    "salt":"5ff63326ca055a6dca267985c8ca03732b907b4197eb16a60c723bd567883650",
    //默克尔验证路径
    "merklesibling":"b6234c998b586914c76ccabd35c97be779074ea2ea7d03e81b25dc80547ee799 02a9c8c6a60eaab5765f526b4a1792f37e3b399cdab2a9492653dac432f2ccd3 5109396c42763abe94aa92acf11e9b2a034cdd1a63a4493ae0cce9fffb632f81 5bd2b306f156bdab383e352dc31c62cb2e18ada75957398fdd0c369ef3850d97 73af5df5f4c36d1377bd976a4b7be2b88878befd21b75962863d22299d3023a6 537ad98582a606ef422881bf766550bf22dbd8f06eb91d6ea59a57643f02c22a 4b590775b2fddd7fa7b6fe428e5ff83256dfbf6a15fa2c30b643a41785c245a0",
    //默克尔根哈希
    "merkleRoot":"806de4a868682738bb328a4801c09d88a93ce1301e3dbff08f5b0881be01fddb",
    //公安机关对默克尔根的签名
    "rootSignature":"3077022051757c2de7032a0c887c3fcef02ca3812fede7ca748254771b9513d8e255",
    //用的公安机关哪个Key进行的签名
    "signer":"did:公安部门ID#keys-1"
  },
  
  }],
  // Holder小明对本VP的签名信息
  "proof": {
    "type": "Secp256k1",
    "created": "2010-07-02T21:19:10Z",
    "proofPurpose": "authentication",
    "verificationMethod": "did:cid:511112200001010015#keys-1",
    // challenge和domain是为了防止重放攻击而设计的
    "challenge": "1f44d55f-f161-4938-a659-f8026467f126",
    "domain": "4jt78h47fh47",
    "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..kTCYt5
      XsITJX1CxPCT8yAV-TVIw5WEuts01mq-pQy7UJiN5mgREEMGlv50aqzpqh4Qq_PbChOMqs
      LfRoPsnsgxD-WUcX16dUOqV0G_zS245-kronKb78cPktb3rk-BuQy72IFLN25DYuNzVBAh
      4vGHSrQyHUGlcTwLtjPAnKb78"
  }
}

0x5. Verifier:验证VP

商家在收到顾客生成的VP后,可以直接通过签名验证默克尔根是否是公安机关签名的,然后通过默克尔验证来证明”2002:1“这个断言是正确的。具体验证的细节我在上一篇文章中已经讲过,这里也是一样的过程,就不再重复了。

0x6. 小结

本文提出的零知识证明方法基于范围数据构建和加盐默克尔树验证,对于无法定范围的场景,可能并不是很适用。比如对于姓名字段,我们可以拆分成姓和名,姓字段是有一个范围的,大概率都在百家姓里面 ,而名字段就太广泛了,基本上所有的汉字都可以作为名,而且名有多个字,排列组合的情况是天文数字,所以我们可以对姓字段建立零知识证明,而对于名字段无法使用。除了生日外,民族是一个可数的范围(56个民族+其他),住址的省、市、县都是一个可数的范围,我们都可以使用本文中的零知识证明方法。

本零知识证明还有个局限性,就是只能证明范围数据构建时的取值,而无法证明中间的取值。比如我们对家庭年收入字段建立范围取值,每10W一个值,所以默克尔树叶子节点就是:[0,10W,20W,30W …...]

比如小明的实际家庭年收入是38W,我们可以基于这个取值来证明家庭年收入大于30W,但是我们无法证明家庭年收入大于35W。如果想要证明,我们就需要将划分范围的粒度变细,比如变成每一个范围是1W,这样构建了一个新的长了很多的叶子节点列表[0,1W,2W,3W…….]如果我们将范围上限定在1000W,那么就需要1000个叶子节点,但是我们也只能证明年收入大于35W,无法证明更细的粒度,比如年收入是否达到38.5W?

基于前面几篇文章介绍的数字身份DID技术的基础知识,下一篇我们将介绍DID的应用场景。

posted @ 2020-12-30 14:06  深蓝  阅读(1567)  评论(2编辑  收藏  举报

我要啦免费统计