Ethereum 用ZoKrates写电路证明年龄超过21岁

Ethereum 用ZoKrates写电路证明年龄超过21岁,ethereum,solidity,proof,Ethereum,Solidity,Proof,我想看看我是否可以在一个场景中使用ZoKrates,在这个场景中,用户可以向验证者证明年龄超过21岁,而不透露出生日期。我认为这是一个很好的零知识证明用例,但我想了解实现它的最佳方法 电路代码(示例)将用户的姓名作为公共输入(姓名认证由DMV等受信任的机构完成,很可能是离线/在线机制的组合),然后是作为私人输入的出生日期 //8297122105 = "Razi" is decimal. def main(pubName,private yearOfBirth, private centuryO

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

电路代码(示例)将用户的姓名作为公共输入(姓名认证由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 
问题

考虑这样一个场景:用户(比如Razi)可以获取上面的证明(可能是二维码的形式),并在一台机器上扫描(确认年龄超过21岁),该机器将在合同上运行verifierTx方法。由于证据中明确地有“Razi”,合同可以在不知道实际出生日期的情况下核实年龄,因此我们获得了更好的隐私。然而,现在的挑战是,任何其他人都可以重用证据,因为它是在事务中使用的。缓解此问题的一种方法是确保证据在有限的时间内有效,或者(仅适用于一次性使用)。另一种方法是确保用户身份证明(“Razi”),以一种毫无疑问令人满意的方式(例如通过在区块链上确认身份等)

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


我希望这个问题和解释有意义。很高兴对此进行详细说明,请让我知道

您需要的是:

  • 拥有以太坊公钥/私钥的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
def main(专用字段salt、专用字段birthdayAsUnixTs、字段publifacthasha、字段publifacthashb、字段ts)->(字段)
//检查事实是否与已背书的盐渍事实指纹链相对应
h0,h1=SHA256包装(0,0,盐,生日)
h0==pubFactHashA
h1==pubFactHashB
//18年只是伪代码!

field ok=如果生日是*18岁你可以通过散列证据并将该散列添加到“用过的证据”列表中来实现,这样就没有人可以再次使用它了

现在,佐克拉特在证据的生成过程中增加了随机性,以防止披露使用了相同的证人,因为证据没有显示证人的任何情况。因此,如果您想阻止此人多次使用其凭证(证明他已超过21岁),您必须使用空值器(请参阅“如何应用zk SNARK创建屏蔽交易”部分中的方法)

基本上,您使用一个包含Razi
nullizer\u string=centuryOfBirth+yearOfBirth+pubName数据的字符串,然后将其散列
nullizer=H(nullizer\u string)
发布到一个显示的nullizers表中。在ZoKrates方案中,您必须将调零器添加为公共输入,然后验证调零器是否对应于提供的数据。大概是这样的:

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 
将“utils/pack/unpack128.code”作为解包导入
将“hashes/sha256/256bitPadded.code”作为哈希导入
将“utils/pack/nonStrictUnpack256.code”作为解压文件导入
def main(pubName、private Yearof Birth、private centuryOfBirth、[2]字段空值器):
字段x=如果centuryOfBirth==19,则为1,否则为0 fi
字段y=若出生年份<98,则1否则0 fi
字段z=如果pubName==8297122105,则为1,否则为0
总计=x+y+z
结果=如果总数==3,则为1,否则为0
null0=unpack(置零器[0])
null1=解包(置零器[1])
nullbits=[…null0,…null1]
nullString=centuryOfBirth+yearOfBirth+pubName
unpackNullString=unpack256(nullString)
空位==散列(解包空字符串)
返回结果
这样做是为了防止Razi提供与他的数据无关的随机置零器

完成此操作后,如果已在显示的空值生成器表中注册,则可以检查提供的空值生成器是否已被使用

在你的例子中,这个问题是出生年份是一个很弱的数字。有人可以对取消者进行蛮力攻击,并揭示拉齐的出生年份。您必须在验证中添加一个强数字(Razi secret ID?数字签名?)以防止此攻击

注1:我有一个旧版本的ZoKrates,所以请检查正确的导入路径


注2:检查ZoKrates散列函数的实现,输入的填充可能会有问题,解压256函数可能会阻止这一点,但您可以再次检查以防止出现错误。

请注意,问题部分中实际上没有问题,只有语句。问题是什么?添加了其他详细信息。
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