实验步骤
基于区块链智能合约实现多方参与的YES/NO投票,并在参与方本地对数据进行隐私保护。1实现智能合约投票协议编写支持多方参与的智能合约投票协议支持参与方注册,由发起方审核注册可指定投票开始与结束时间
实验过程和摘要
2支持参与方对自身数据进行隐私保护采用随机响应对YES/NO投票进行理论严格的差分隐私保护
其中GS_f的是函数f的GS。GS_f取值为:对于拉普拉斯算法,他的mean为0,``variance是2∗variance越小,说明处理之后的数据集的utility越高。但是,从variance的公式我们可以得知variance和ε成反比,也就是说ε和utility成反比。因此,单纯的追求隐私保护或高utility都会损坏另外一方。在实际需求中,我们需要寻找一个平衡点。
实验前,复习《数据隐私保护技术》与《区块链技术》课程中的有关内容。准备好实验数据,编程完成实验内容,收集实验结果。独立完成实验报告。
基本要求
电子投票系统的一个主要问题是如何分配合理的权限给正确的人,并且要防止篡改。首先要为投票设立一个简称创建一个合约,发起者作为主席来给每一个独立的地址分配权限。每一个参与者可以自己投票或者委托给信任的人。程序最后会返回得票数最多的那个提议。其次需要保证投票统计数据库的查询结果不会受到任何单一用户的隐私数据的影响。采用中心化差分隐私,ε-差分隐私的定义如下:
实验内容:
合约Dapp部署使用Node.js建立开启服务器,部署Dapp合约。映射监听端口。
主体实验代码
// 从所有的提案中找出最大投票数的提案,作为最终的方案。
pragma solidity >=0.4.22;
contract Myballot{
//投票人
struct Voter{
bool voted; //是否投票
uint weight; //权重
uint8 vote_id; //投给哪个提案id,就是数组下标
address delegate; //投票权委托人
}
//提案
struct Proposal{
string name; //提案名字
string content; //提案内容
uint voteCount; //被投票数
bool enable; //启动
}
//主席
address public chairperson;
//可变长度数组,放置所有提案,下标与提案id对应,不用mapping的原因是方便遍历。
Proposal[] public proposals;
//当前的提案数
uint public nowNumProposal;
//Uint8的最大值
uint public UINT8_MAX_VALUE = (2**8)-1;
//投票人映射
mapping(address=>Voter) public voters;
constructor(uint _chairpersonWight) public{
//设置主席的初始参数
chairperson = msg.sender;
voters[chairperson].weight = _chairpersonWight;
//定义提案数组长度
// +1 是因为默认值0的数组位置不给用,从1开始
proposals.length = UINT8_MAX_VALUE + 1;
}
//提案申请
function applyProposal(string _proposalName, string _proposalContent) public{
//检查提案数量是否已满
require(nowNumProposal < UINT8_MAX_VALUE, "提案已满");
//提案数加1
++nowNumProposal;
//录入提案信息
proposals[nowNumProposal].name = _proposalName;
proposals[nowNumProposal].content = _proposalContent;
proposals[nowNumProposal].enable = true;
}
//仅主席可调用
modifier Onlychairperson{
require(msg.sender == chairperson, "仅主席可操作");
_;
}
//检查某人是否还有投票权
modifier haveVoted(address someone){
require(voters[someone].voted == false, "投票权已使用");
_;
}
//授权投票人
function authorizedVote(address _voter, uint _weight) public Onlychairperson haveVoted(_voter){
require(_weight >= 0 && _weight <= 100, "投票权重范围超出");
require(voters[_voter].weight == 0, "只允许赋权一次");
voters[_voter].weight = _weight;
}
//代理投票
function delegateVoting(address _to) public haveVoted(msg.sender){
//重点!!!
//代理会出现多重代理,要使用while找到目的地
require(_to != msg.sender, "不能将代理权给自己"); //设置后所有人都不可能自循环
//循环的目的:找到多重代理的最终者
//继续迭代条件(while条件):
//①代理者的下一个代理人存在 voters[_to].delegate != address(0)
//②不能代理回之前的代理人(造成环)若成环那么环中的人一定会调回到自己,后面的判断就生效 voters[_to].delegate != msg.sender
//③不能自循环(上面已保证)
while(voters[_to].delegate != address(0) && voters[_to].delegate != msg.sender)
_to = voters[_to].delegate; //迭代,将代理人的代理变为下一个代理_to
require(voters[_to].delegate != msg.sender, "不可循环代理");
//表示代理
voters[msg.sender].delegate = _to;
if(voters[_to].voted){
//如果代理人已经投过票了,那么就把权重累加到已投的提案
proposals[voters[_to].vote_id].voteCount += voters[msg.sender].weight;
voters[msg.sender].vote_id = voters[_to].vote_id;
}else{
//没投那么就把权重交给代理人
voters[_to].weight += voters[msg.sender].weight;
}
voters[msg.sender].voted = true;
}
//投票函数
function vote(uint8 _proposalID) public haveVoted(msg.sender){
require(_proposalID >= 0 && _proposalID <= UINT8_MAX_VALUE, "投票提案ID范围超出");
require(proposals[_proposalID].enable, "提案未开启");
proposals[_proposalID].voteCount += voters[msg.sender].weight;
voters[msg.sender].vote_id = _proposalID;
voters[msg.sender].voted = true;
}
//当前获胜提案
function winningProposal() public view returns(string name, uint maxProposalID, uint maxVoteCount){
require(nowNumProposal > 0, "当前无提案");
for(uint i = 1; i <= nowNumProposal; i++){
if(proposals[i].voteCount > maxVoteCount){
maxVoteCount = proposals[i].voteCount;
maxProposalID = i;
name = proposals[i].name;
}
}
require(maxVoteCount > 0, "当前无提案被投票");
}
}
形化界面设计并与合约连接使用react编写投票前台程序,用于构成用户界面进行投票操作。操纵Web3的接口以连接合约层。
3发起方对隐私保护的投票结果进行无偏解码利用随机响应的无偏估计方法得到投票结果
原理
投票响应测试
安装需要的依赖
测试投票功能是否成功,是否能够在以太链上产生一笔交易。
代码
4测试和评估系统测试准确性和效率
主体合约代码编写编写主体合约的代码,包括设置提案,设置投票票数以及提案。例如编写如下主体代码:structVoter{boolvoted;//是否投票uintweight;//权重uint8vote_id;//投给哪个提案id,就是数组下标addressdelegate;//投票权委托人}代表委托投票信息。将随机响应的机制应用于智能合约运用随机响应的机制,使用js语言实现智能合约的随机响应对YES/NO投票进行理论严格的差分隐私保护。合约编译部署使用Truffle编译部署合约,并产生1_initial_migration.js与2_deploy_contracts.js文件供后续提供ABI接口,ABI用于连接合约层与应用层。监听8545端口用于metamask的本地钱包,与此同时创建出10个以太链上的账户,用于测试执行投票程序。
这里的随机函数A是运行在服务器上面的,本地用户不需要运行任何差分隐私算法。ε可以看做是隐私预算,它用来量化一个用户隐私泄露的风险。ε的值越大,隐私泄露的风险就越大,反之,ε越小,隐私泄露的风险就越小。本实验的扰动方案对输入数据进行扰动,加入噪音,使其满足ε-差分隐私。对于输入数据扰动的典型方案就是随机响应,对于输出数据扰动的典型方案就是拉普拉斯算法。拉普拉斯算法在真实投票选项f的基础上加上符合拉普拉斯分布的噪音。噪音η的取值公式为:
实验结果分析
代码构成
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ └── src //前端界面代码
│ ├── App.js
│ ├── Ballot.js
│ ├── HeadBar.js
│ ├── Home.js
│ ├── contracts
│ │ ├── Election.json
│ │ └── Migrations.json
│ ├── getWeb3.js //合约交互
│ ├── index.js
│ ├── serviceWorker.js
│ └── theme.js
├── contracts
│ ├── Election.sol //合约主体代码
│ └── Migrations.sol
├── migrations //部署合约代码
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── truffle-box.json //Truffle依赖文件
├── truffle-config.js
└── yarn.lock
文章为作者独立观点,不代表股票交易接口观点