【问题标题】:Writing a circuit in ZoKrates to proof age is over 21 years在 ZoKrates 中编写电路以证明年龄超过 21 岁
【发布时间】:2019-01-07 08:46:35
【问题描述】:

我想看看我是否可以在用户可以向验证者证明年龄超过 21 岁而不透露出生日期的情况下使用 ZoKrates。我认为它是零知识证明的一个很好的用例,但想了解实现它的最佳方式。

电路代码(示例)将用户的姓名作为公共输入(姓名认证由 DMV 等受信任的机构完成,并且很可能是离线/在线机制的组合),然后是出生日期私人输入。

//8297122105 = "Razi" is decimal.
def main(pubName,private yearOfBirth, private centuryOfBirth):
  x = 0
  y = 0
  z = 0
  x = if centuryOfBirth == 19 then 1 else 0 fi
  y = if yearOfBirth < 98 then 1 else 0 fi
  z = if pubName == 8297122105 then 1 else 0 fi
  total =  x + y + z 
  result = if total == 3 then 1 else 0 fi

  return result 

现在,使用./target/release/zokrates generate-proof 命令获取可用作verifier.sol 输入的输出。

A = Pairing.G1Point(0x24cdd31f8e07e854e859aa92c6e7f761bab31b4a871054a82dc01c143bc424d, 0x1eaed5314007d283486826e9e6b369b0f1218d7930cced0dd0e735d3702877ac);
A_p = Pairing.G1Point(0x1d5c046b83c204766f7d7343c76aa882309e6663b0563e43b622d0509ac8e96e, 0x180834d1ec2cd88613384076e953cfd88448920eb9a965ba9ca2a5ec90713dbc);
B = Pairing.G2Point([0x1b51d6b5c411ec0306580277720a9c02aafc9197edbceea5de1079283f6b09dc, 0x294757db1d0614aae0e857df2af60a252aa7b2c6f50b1d0a651c28c4da4a618e], [0x218241f97a8ff1f6f90698ad0a4d11d68956a19410e7d64d4ff8362aa6506bd4, 0x2ddd84d44c16d893800ab5cc05a8d636b84cf9d59499023c6002316851ea5bae]);
B_p = Pairing.G1Point(0x7647a9bf2b6b2fe40f6f0c0670cdb82dc0f42ab6b94fd8a89cf71f6220ce34a, 0x15c5e69bafe69b4a4b50be9adb2d72d23d1aa747d81f4f7835479f79e25dc31c);
C = Pairing.G1Point(0x2dc212a0e81658a83137a1c73ac56d94cb003d05fd63ae8fc4c63c4a369f411c, 0x26dca803604ccc9e24a1af3f9525575e4cc7fbbc3af1697acfc82b534f695a58);
C_p = Pairing.G1Point(0x7eb9c5a93b528559c9b98b1a91724462d07ca5fadbef4a48a36b56affa6489e, 0x1c4e24d15c3e2152284a2042e06cbbff91d3abc71ad82a38b8f3324e7e31f00);
H = Pairing.G1Point(0x1dbeb10800f01c2ad849b3eeb4ee3a69113bc8988130827f1f5c7cf5316960c5, 0xc935d173d13a253478b0a5d7b5e232abc787a4a66a72439cd80c2041c7d18e8);
K = Pairing.G1Point(0x28a0c6fff79ce221fccd5b9a5be9af7d82398efa779692297de974513d2b6ed1, 0x15b807eedf551b366a5a63aad5ab6f2ec47b2e26c4210fe67687f26dbcc7434d);

问题

假设用户(比如 Razi)可以获取上述证明(可能以 QR 码的形式)并在将在合约上运行 verifierTx 方法的机器上扫描它(确认年龄超过 21 岁) .由于证明在证明中明确包含“Razi”,并且合约可以在不知道实际出生日期的情况下验证年龄,我们可以获得更好的隐私。然而,现在的挑战是任何其他人都可以重用证明,因为它在交易中使用过。缓解此问题的一种方法是确保证明在有限时间内有效,或者(可能只适合一次性使用)。另一种方法是确保用户身份的证明(“Razi”),以一种毫无疑问的方式(例如,通过在区块链上确认身份等)。

有没有办法确保用户可以多次使用证明?

我希望问题和解释是有意义的。很高兴详细说明这一点,所以让我知道。

【问题讨论】:

  • 请注意,您在问题部分实际上没有问题,只有陈述。问题是什么?
  • 添加了更多详细信息。

标签: ethereum solidity proof


【解决方案1】:

你需要的是:

  • Razi 拥有以太坊公钥/私钥
  • 与 Razi 的公共以太坊地址相关联并由权威机构在链上认可的(加盐)指纹事实(例如,作为 unix 时间戳的生日)

现在你可以像这样编写一个 ZoKrates 程序

def main(private field salt, private field birthdayAsUnixTs, field pubFactHashA, field pubFactHashB, field ts) -> (field)
    // check that the fact is corresponding to the endorsed salted fact fingerprint onchain
    h0, h1 = sha256packed(0,0,salt,birthdayAsUnixTs)
    h0 == pubFactHashA
    h1 == pubFactHashB

    // 18 years is pseudo code only!
    field ok = if birthdayAsUnixTs * 18 years <= ts then 1 else 0 fi

    return ok

现在你可以在合同中

  • 检查 msg.sender 是背书事实的所有者
  • 需要(ts
  • 使用证明和公共输入调用验证器:(factHash, ts, 1)

【讨论】:

    【解决方案2】:

    您可以通过对证明进行散列处理并将该散列添加到“已使用证明”列表中来做到这一点,这样就没有人可以再次使用它了。

    现在,ZoKrates 在证明的生成中添加了随机性,以防止泄露使用了相同的证人,因为 zkproofs 不会显示任何关于证人的信息。因此,如果您想阻止该人多次使用他的凭证(确认他已超过 21 岁),您必须使用无效符(请参阅“如何应用 zk-SNARKs 来创建屏蔽交易”部分)。

    基本上,您使用带有 Razi nullifier_string = centuryOfBirth+yearOfBirth+pubName 数据的字符串,然后将其 Hash nullifier = H(nullifier_string) 发布到已显示的无效符表中。在 ZoKrates 方案中,您必须将 nullifier 添加为公共输入,然后验证 nullifier 是否与提供的数据相对应。像这样的:

    import "utils/pack/unpack128.code" as unpack
    import "hashes/sha256/256bitPadded.code" as hash
    import "utils/pack/nonStrictUnpack256.code" as unpack256
    
    def main(pubName,private yearOfBirth, private centuryOfBirth, [2]field nullifier):
    
      field x = if centuryOfBirth == 19 then 1 else 0 fi
      field y = if yearOfBirth < 98 then 1 else 0 fi
      field z = if pubName == 8297122105 then 1 else 0 fi
      total =  x + y + z 
      result = if total == 3 then 1 else 0 fi
    
      null0 = unpack(nullifier[0])
      null1 = unpack(nullifier[1])
      nullbits = [...null0,...null1]
    
      nullString = centuryOfBirth+yearOfBirth+pubName
      unpackNullString = unpack256(nullString)
    
      nullbits == hash(unpackNullString)
    
    
      return result 
    

    这样做是为了防止 Razi 提供一个与他的数据无关的随机无效值。

    完成此操作后,您可以检查提供的无效符是否已被使用(如果它已在显示的无效符表中注册)。

    在您的情况下,问题在于出生年份是一个难以散列的数字。有人可以对无效器进行暴力攻击,并显示 Razi 的出生年份。您必须在验证中添加一个强数字(Razi 秘密 ID?数字签名?)以防止这种攻击。

    注意1:我有旧版本的ZoKrates,请检查正确的导入路径。

    注意2:检查ZoKrates Hash函数实现,输入的填充可能有问题,我想unpack256函数可以防止这种情况,但你可以仔细检查以防止出现错误。

    【讨论】:

      猜你喜欢
      • 2010-12-21
      • 2018-05-11
      • 1970-01-01
      • 2020-10-02
      • 2022-01-22
      • 2022-07-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-22
      相关资源
      最近更新 更多