区块链上安全且隐私保护的投票系统-数据隐私保护技术与区块链技术实验

一、概述

1.设计名称:区块链上安全且隐私保护的投票系统
2.实验目的:本实验课程是计算机、网络安全、软件工程等专业学生的一门专业课程,通过实验,帮助学生更好地掌握数据隐私保护与区块链相关概念、技术、原理、应用等;通过实验提高学生编写实验报告、总结实验结果的能力;使学生对区块链模型、智能合约、隐私保护算法等有比较深入的认识。要掌握的知识点如下:
1)掌握区块链中涉及的相关概念、模型、算法;
2)熟悉智能合约原理、开发与测试的流程;
3)熟悉常用的数据隐私保护方法。
3.编程语言:Solidity、JavaScript

二、基本要求

1.实验前,复习《数据隐私保护技术》与《区块链技术》课程中的有关内容。
2.准备好实验数据,编程完成实验内容,收集实验结果。
3.独立完成实验报告。

三、实验内容:

基于区块链智能合约实现多方参与的YES/NO投票,并在参与方本地对数据进行隐私保护。
1 实现智能合约投票协议
编写支持多方参与的智能合约投票协议
(可选)支持参与方注册,由发起方审核注册
(可选)可指定投票开始与结束时间

2 支持参与方对自身数据进行隐私保护
采用随机响应(randomized response)对YES/NO投票进行理论严格的差分隐私保护

3 发起方对隐私保护的投票结果进行无偏解码
利用随机响应的无偏估计方法得到投票结果

4 测试和评估系统
测试准确性和效率

四、实验过程和摘要

1. 原理

电子投票系统的一个主要问题是如何分配合理的权限给正确的人,并且要防止篡改。首先要为投票设立一个简称创建一个合约,发起者作为主席来给每一个独立的地址分配权限。每一个参与者可以自己投票或者委托给信任的人。程序最后会返回得票数最多的那个提议。
其次需要保证投票统计数据库的查询结果不会受到任何单一用户的隐私数据的影响。采用中心化差分隐私ε-差分隐私(ε-DP)的定义如下:

这里的随机函数 A 是运行在服务器上面的,本地用户不需要运行任何差分隐私算法。ε 可以看做是隐私预算,它用来量化一个用户隐私泄露的风险。ε 的值越大,隐私泄露的风险就越大,反之,ε越小,隐私泄露的风险就越小。
本实验的扰动方案对输入数据进行扰动,加入噪音,使其满足 ε-差分隐私。对于输入数据扰动的典型方案就是随机响应, 对于输出数据扰动的典型方案就是拉普拉斯算法
请添加图片描述
拉普拉斯算法在真实投票选项f(D)的基础上加上符合拉普拉斯分布的噪音。噪音 η 的取值公式为:
请添加图片描述

其中 GS_f 的是函数 f 的 GS(global sensitivity)。GS_f 取值为:
请添加图片描述
对于拉普拉斯算法,他的 mean0,``variance2 ∗ (GS_f)2。variance 越小,说明处理之后的数据集的 utility 越高。但是,从 variance 的公式我们可以得知 variance 和 ε 成反比,也就是说 ε utility 成反比。因此,单纯的追求隐私保护或高utility都会损坏另外一方。在实际需求中,我们需要寻找一个平衡点

2. 代码

代码构成

│   ├── 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

主体实验代码

// 从所有的提案中找出最大投票数的提案,作为最终的方案。

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, "当前无提案被投票");
    }
}

3.实验步骤

  1. 主体合约代码编写
    编写主体合约的代码,包括设置提案,设置投票票数以及提案。例如
    编写如下主体代码:
    struct Voter{
    bool voted; //是否投票
    uint weight; //权重
    uint8 vote_id; //投给哪个提案id,就是数组下标
    address delegate; //投票权委托人
    }
    代表委托投票信息。

  2. 将随机响应的机制应用于智能合约
    运用随机响应的机制,使用js语言实现智能合约的随机响应(randomized response)对YES/NO投票进行理论严格的差分隐私保护。

  3. 合约编译部署
    使用Truffle编译部署合约,并产生1_initial_migration.js2_deploy_contracts.js文件供后续提供ABI接口,ABI(Application Binary Interface)用于连接合约层与应用层。监听8545端口用于metamask的本地钱包,与此同时创建出10个以太链上的账户,用于测试执行投票程序。

请添加图片描述
4. 图形化界面设计并与合约连接
使用react编写投票前台程序,用于构成用户界面进行投票操作。操纵Web3的接口以连接合约层。

请添加图片描述

5.合约Dapp部署
使用Node.js 建立开启服务器,部署Dapp合约。映射监听端口。

请添加图片描述

  1. 投票响应测试

测试投票功能是否成功,是否能够在以太链上产生一笔交易。
请添加图片描述

五、实验结果分析

程序使用步骤如下:

  1. 安装需要的依赖
  • Npm
    想要取得安装信息 , 从 https://nodejs.org/en/ 获取
  • Metamask
    一个加密的区块链钱包, 从 https://metamask.io 获取
  • Yarn(可选)
    Yarn是一个Javascript的包管理工具,其修补了许多NPM的缺陷。
  1. 使用Truffle打包合约并创建测试账户

  2. 启动前台页面渲染

  3. 启动metamask并进行投票

  4. 发起投票方公布投票结果 请添加图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

vimtion

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值