零知识证明三—— 如用zksnarks方式构建一个匿名投票系统

 这个匿名投票系统的例子还是不完善的,如果你有好的建议和想法可以留言一起学习探讨。 

https://github.com/XuHugo/zksnarks-election/tree/master   

 一、构建一个匿名的投票系统,最核心的部分有两个,

         1、投票人的匿名

         2、投票人身份合法性确认

    如何解决这个两个核心问题?

     第一个问题,投票人的匿名,首先我们规定每个人又一个私钥代表每个人,然后将私钥做hash作为id,这样即使暴露了id也无法知晓每个人的身份。然后投票的时候,我们让投票人不发送任何关于自己身份的信息(私钥和id都不发出去)就可以了;

    第二个问题,身份合法性,我们构造一个merkle tree,叶子的信息是每个人的id,然后验证身份的时候,验证者需要提供私钥和验证路径就可以得到root节点的hash值。而从root则无法返推出个人的id;而有人想要冒充别人身份投票的时候,也没有相关的信息去证明自己身份的合法性。

    二、zksnarks的思路

     我们把zksnark的方法流程化,方便我们工程化;

     1、生成一个约束函数Circuit(),这一步可以认为是R1CS。circuit=Circuit()

     2、根据约束,生成proof_key和verification_key;{proof_key,verification_key}=setup(circuit)

     3、生成证明proof;proof=Proof(proof_key, public_signal, witness)

     4、验证是否正确;Verifier(verification_key, public_signal, proof)

三、代码实现

   这里第一二部分,我用python简单实现一下这个工程;

    第一部分讲一下merketree,这里我是用一个类表示的;

class Merkletree():
    #初始化,number要创建能够容纳用户,但是其表示2的number次幂,例如number=3,则表示
    #有8个人投票;hash_id是一个列表,是所有用户id的集合;
    #初始化函数,使用字典构建一个tree结构,包含了从叶子节点一直到根节点所有hash值;
    def __init__(self, number, hash_id):
        self.tree={}
        self.number=number
        for i in range(number, -1, -1):
            tree_tmp={}
            for j in range(1, 2**i+1, 1):
                if i==number:
                    tree_tmp[j]=hash_id[j-1]
                else:
                    tree_tmp[j]=Hash(self.tree[i+1][j*2-1]+self.tree[i+1][j*2])
            self.tree[i]=tree_tmp
    #获取根节点hash
    @property
    def root(self):
        return self.tree[0][1]
    #用户输入number(这里的nubmer表示的是叶子节点的顺序,从1开始依次+1)
    #根据number,生成用户验证路径,返回一个列表
    def path(self, number):
        path=[]
        num=number
        for i in range(self.number, 0, -1):
            if num%2==0:
                path.append(self.tree[i][num-1])
                num=int(num/2)
            else:
                path.append(self.tree[i][num+1])
                num=int((num+1)/2)
        return path

第二部分,展示一下zksnarks的实现;

class zksnarks():

    def __init__(self):
        pass
    #这里是约束函数
    def Circuit(self, pub, witness):
        return (Hash(witness["private"]) in id_hash
                and pub["root"]==GetTreeRoot(Hash(witness["private"]),witness["path"])
                and pub["vote_hash"]==Hash(witness["private"]+pub["vote"]))
    #通过约束函数,生成证明密钥和验证密钥
    def Setup(self, key):
        proof_key = key + id(self.Circuit)
        verify_key = key - id(self.Circuit)
        return proof_key,verify_key
    #生成proof
    def Proof(self, proof_key, pub, witness):
        proof = proof_key+self.Circuit(pub, witness)+int(Hash(str(pub))[:6],16)
        return proof
    #验证函数
    def Verify(self, verify_key, pub, proof):
        result = verify_key+2*id(self.Circuit)+1+int(Hash(str(pub))[:6],16)
        return result==proof

第三部分,就是如何使用了;

#生成随机用户私钥以及私钥hash的函数(id),初始化自己生成一套即可;其实3表示2的3次幂=8
#private_key=random_id(3)
#id_hash=hash_id(private, 3)

private_key=['8735', '0364', '8927', '3941', '8931', '7150', '1824', '4083']
id_hash=['cc4996f23b1298387d649919eaa4f4f1f1c26ef836af118ca1334a366efbf979', 'b9ff439e33f8f6f58616593936746d86adc8163a38bc44580d2bbc2ffc965a62', '1211b78610929c31e748981c4df7adba9b068e63fd887ec1a3b1af46c2dba1c1', '6621ead3c9ec19dfbd65ca799cc387320c1f22ac0c6b3beaae9de7ef190668c4', '699415a6e63027a2c3cb8fcb891dab4c62a28b6a15dbe6ccf5dab0126c02505b', '02cf62656564decc54131e85c0415cbad4eb573a24278854fe8bc4aa3fe45268', '2ced184d8477465987593807f31360e94b539aa41f515e0a973179f881663698', 'd0ab3354a660b3abcb7829c7636981ddc8ce4a68c943947081ff8399f063f786']

#生成随机秘钥
random_key = getrandbits(256)

#这里的3也是指数,生成一个8人的tree,另外一个参数是用户id集合;
mtree=Merkletree(3,id_hash)

#正确的身份投票Jordan,验证通过
vote="Jordan" #投票内容
vote_hash=Hash(private_key[0]+vote)  #由于发送投票结果可能会被截获,所以和用户的私钥绑定
witness={"private":private_key[0],"path":mtree.path(1)} 
pub={"root":mtree.root,"vote":vote, "vote_hash":vote_hash}#这一部分就是用户需要发送投票结果,里边没有包含任何个人身份信息

zk=zksnarks()
pk, vk=zk.Setup(random_key)#生成vk,pk
proof=zk.Proof(pk,pub,witness)
ret=zk.Verify(vk,pub,proof)
print("vote:",pub["vote"],"   result:",ret)


#错误的身份投票Jordan,验证失败
vote="Jordan"
vote_hash=Hash("6666"+vote)
witness={"private":"6666","path":mtree.path(1)}
pub={"root":mtree.root,"vote":vote, "vote_hash":vote_hash}

zk=zksnarks()
pk, vk=zk.Setup(random_key)
proof=zk.Proof(pk,pub,witness)
ret=zk.Verify(vk,pub,proof)
print("vote:",pub["vote"],"   result:",ret)

ok,到这里就结束了。看一下运行结果。

 

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xweb3q

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值