Integrated EZPC helper file (#18)

* Added EZPC helper file, updated output, added shift tests
This commit is contained in:
Edward Chen
2021-09-02 18:08:08 -04:00
committed by GitHub
parent d9d66896b3
commit 92cff0a119
36 changed files with 366 additions and 73 deletions

View File

@@ -0,0 +1,5 @@
def main(private<1> u32 a, private<2> u32 b) -> u32:
for u32 i in 1..4 do
a = a + b
return a

View File

@@ -0,0 +1,2 @@
def main(private<1> u32 a, private<2> u32 b) -> u32[2]:
return [a, b]

View File

@@ -0,0 +1,3 @@
def main(private<1> u32 a, private<2> u32 b) -> u32:
u32[2] c = [a, b]
return c[0] + c[1]

View File

@@ -0,0 +1,5 @@
def sum(u32 a, u32 b) -> u32:
return a + b
def main(private<1> u32 a, private<2> u32 b) -> u32:
return sum(a, b)

View File

@@ -0,0 +1,3 @@
def main(private<1> u32 a, private<2> u32 b) -> u32:
u32 c = 0x00000001
return a << c

View File

@@ -0,0 +1,3 @@
def main(private<1> u32 a, private<2> u32 b) -> u32:
u32 c = 0x00000001
return a >> c

View File

@@ -61,7 +61,8 @@ fn main() {
Mode::Opt => opt(cs, vec![Opt::ConstantFold]),
Mode::Mpc(_) => opt(
cs,
vec![Opt::Sha, Opt::ConstantFold, Opt::Mem, Opt::ConstantFold],
vec![],
// vec![Opt::Sha, Opt::ConstantFold, Opt::Mem, Opt::ConstantFold],
),
Mode::Proof => opt(
cs,

View File

@@ -24,50 +24,54 @@ function mpc_test {
}
# build mpc arithmetic tests
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_add.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_sub.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_mult.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_mult_add_pub.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_add.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_sub.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_mult.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_mult_add_pub.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_int_equals.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_int_greater_than.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_int_greater_equals.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_int_less_than.zok
mpc_test 2 ./examples/ZoKrates/mpc/arithmetic_tests/2pc_int_less_equals.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_int_equals.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_int_greater_than.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_int_greater_equals.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_int_less_than.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/arithmetic_tests/2pc_int_less_equals.zok
# build mpc nary arithmetic tests
mpc_test 2 ./examples/ZoKrates/mpc/nary_arithmetic_tests/2pc_nary_arithmetic_add.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/nary_arithmetic_tests/2pc_nary_arithmetic_add.zok
# build mpc bitwise tests
mpc_test 2 ./examples/ZoKrates/mpc/bitwise_tests/2pc_bitwise_and.zok
mpc_test 2 ./examples/ZoKrates/mpc/bitwise_tests/2pc_bitwise_or.zok
mpc_test 2 ./examples/ZoKrates/mpc/bitwise_tests/2pc_bitwise_xor.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/bitwise_tests/2pc_bitwise_and.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/bitwise_tests/2pc_bitwise_or.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/bitwise_tests/2pc_bitwise_xor.zok
# build mpc boolean tests
mpc_test 2 ./examples/ZoKrates/mpc/boolean_tests/2pc_boolean_and.zok
mpc_test 2 ./examples/ZoKrates/mpc/boolean_tests/2pc_boolean_or.zok
mpc_test 2 ./examples/ZoKrates/mpc/boolean_tests/2pc_boolean_equals.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/boolean_tests/2pc_boolean_and.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/boolean_tests/2pc_boolean_or.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/boolean_tests/2pc_boolean_equals.zok
# build mpc nary boolean tests
mpc_test 2 ./examples/ZoKrates/mpc/nary_boolean_tests/2pc_nary_boolean_and.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/nary_boolean_tests/2pc_nary_boolean_and.zok
# build ite tests
mpc_test 2 ./examples/ZoKrates/mpc/ite_tests/2pc_ite_ret_bool.zok
mpc_test 2 ./examples/ZoKrates/mpc/ite_tests/2pc_ite_ret_int.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/ite_tests/2pc_ite_ret_bool.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/ite_tests/2pc_ite_ret_int.zok
# build mpc const tests
mpc_test 2 ./examples/ZoKrates/mpc/const_tests/2pc_const_arith.zok
mpc_test 2 ./examples/ZoKrates/mpc/const_tests/2pc_const_bool.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/const_tests/2pc_const_arith.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/const_tests/2pc_const_bool.zok
# build mpc array tests
mpc_test 2 ./examples/ZoKrates/mpc/array_tests/2pc_array_sum.zok
mpc_test 2 ./examples/ZoKrates/mpc/array_tests/2pc_array_ret.zok
# mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/array_tests/2pc_array_sum.zok
# mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/array_tests/2pc_array_ret.zok
# build mpc function tests
mpc_test 2 ./examples/ZoKrates/mpc/function_tests/2pc_function_sum.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/function_tests/2pc_function_sum.zok
# build mpc shift tests
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/shift_tests/2pc_lhs.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/shift_tests/2pc_rhs.zok
# build mpc misc tests
mpc_test 2 ./examples/ZoKrates/mpc/2pc_millionaire.zok
mpc_test 2 ./examples/ZoKrates/mpc/2pc_conv.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/2pc_millionaire.zok
mpc_test 2 ./examples/ZoKrates/mpc/unit_tests/2pc_conv.zok
# mpc_test 2 ./examples/ZoKrates/mpc/hycc_benchmarks/biomatch.zok

View File

@@ -463,6 +463,43 @@ function_tests = [
]
shift_tests = [
[
"Left Shift a by 1 - 1",
20,
"./third_party/ABY/build/bin/2pc_lhs_test",
{"a": 10, "b": 0},
{"a": 0, "b": 2},
],
[
"Left Shift a by 1 - 2",
0,
"./third_party/ABY/build/bin/2pc_lhs_test",
{"a": 0, "b": 0},
{"a": 0, "b": 2},
],
[
"Left Shift a by 1 - 3",
0,
"./third_party/ABY/build/bin/2pc_lhs_test",
{"a": 2147483648, "b": 0},
{"a": 0, "b": 2},
],
[
"Right Shift a by 1 - 1",
10,
"./third_party/ABY/build/bin/2pc_rhs_test",
{"a": 20, "b": 0},
{"a": 0, "b": 2},
],
[
"Right Shift a by 1 - 2",
0,
"./third_party/ABY/build/bin/2pc_rhs_test",
{"a": 0, "b": 0},
{"a": 0, "b": 2},
],
]
misc_tests = [
[
@@ -550,10 +587,11 @@ def main():
nary_boolean_tests + \
const_tests + \
ite_tests + \
arr_tests + \
function_tests + \
shift_tests + \
misc_tests
# tests = arr_tests
# arr_tests + \
failed_test_descs = []
num_retries = 3

View File

@@ -79,7 +79,7 @@ fn write_test_file(filename: &String) {
);
fs::write(path.clone(), template.replace("{fn}", &*filename))
.expect("Failed to write to cmake file");
.expect("Failed to write to test file");
}
/// Using the h_template.txt, write the .h file for the new test case
@@ -92,7 +92,7 @@ fn write_h_file(filename: &String) {
);
fs::write(path.clone(), template.replace("{fn}", &*filename))
.expect("Failed to write to cmake file");
.expect("Failed to write to h file");
}
/// Using the cpp_template.txt, write the .cpp file for the new test case
@@ -111,7 +111,7 @@ fn write_circ_file(filename: &String, circ: String, output: &String) {
.replace("{circ}", &circ)
.replace("{output}", &output),
)
.expect("Failed to write to cmake file");
.expect("Failed to write to cpp file");
}
/// Write circuit output from translation later to ABY

View File

@@ -188,6 +188,14 @@ impl ToABY {
format!("bcirc->PutCONSGate((uint64_t)1, (uint32_t)1)")
}
fn remove_cons_gate(&self, circ: String) -> String {
if circ.contains("PutCONSGate(") {
circ.split("PutCONSGate(").last().unwrap_or("").split(",").next().unwrap_or("").to_string()
} else {
panic!("PutCONSGate not found in: {}", circ)
}
}
fn embed_eq(&mut self, t: Term, a: Term, b: Term) -> String {
let s_circ = self.get_sharetype_circ(t.clone());
match check(&a) {
@@ -471,8 +479,41 @@ impl ToABY {
)),
);
}
BvBinOp::Shl => {
let b_val = self.remove_cons_gate(b_conv);
self.cache.insert(
t.clone(),
EmbeddedTerm::Bv(format!(
"left_shift({}, {}, {})",
s_circ, a_conv, b_val
)),
);
}
BvBinOp::Lshr => {
let b_val = self.remove_cons_gate(b_conv);
self.cache.insert(
t.clone(),
EmbeddedTerm::Bv(format!(
"logical_right_shift({}, {}, {})",
s_circ, a_conv, b_val
)),
);
}
BvBinOp::Ashr => {
let b_val = self.remove_cons_gate(b_conv);
self.cache.insert(
t.clone(),
EmbeddedTerm::Bv(format!(
"arithmetic_right_shift({}, {}, {})",
s_circ, a_conv, b_val
)),
);
}
_ => panic!("Invalid bv-op in BvBinOp: {:?}", o),
}
}
Op::BvExtract(start, end) => {
}
_ => panic!("Non-field in embed_bv: {:?}", t),
}
@@ -480,51 +521,38 @@ impl ToABY {
self.get_bv(&t)
}
fn embed(&mut self, t: Term) -> String {
let mut output_circ: String = "".to_string();
for c in PostOrderIter::new(t) {
match check(&c) {
Sort::Bool => {
output_circ = self.embed_bool(c);
}
Sort::BitVector(_) => {
output_circ = self.embed_bv(c);
}
e => panic!("Unsupported sort in embed: {:?}", e),
}
}
output_circ
}
/// Given a Circuit `circ`, wrap `circ` in an OUT gate to extract the value of
/// the circuit to a share
///
/// Return a String of the resulting Circuit
fn add_output_gate(&mut self, t: Term, circ: String) -> String {
fn format_output_circuit(&self, t: Term, circ: String) -> String {
format!(
"\ts_out_{} = {}->PutOUTGate({}, ALL);\n",
self.output_counter,
"\tadd_to_output_queue(out_q, {}->PutOUTGate({}, ALL), role, std::cout);\n",
self.get_sharetype_circ(t),
circ
)
}
fn embed(&mut self, t: Term) -> String {
let mut circ = String::new();
for c in PostOrderIter::new(t.clone()) {
match check(&c) {
Sort::Bool => {
circ = self.embed_bool(c);
}
Sort::BitVector(_) => {
circ = self.embed_bv(c);
}
e => panic!("Unsupported sort in embed: {:?}", e),
}
}
self.format_output_circuit(t, circ)
}
/// Given a term `t`, lower `t` to ABY Circuits
fn lower(&mut self, t: Term) {
let mut output_circ = self.embed(t.clone());
output_circ = self.add_output_gate(t, output_circ);
self.aby.circs.push(output_circ);
self.aby
.setup
.push(format!("share *s_out_{};", self.output_counter));
self.aby.output.push(format!(
"uint32_t output_{} = s_out_{}->get_clear_value<uint32_t>();\n
\tstd::cout << output_{} << std::endl;",
self.output_counter, self.output_counter, self.output_counter
));
self.output_counter += 1;
let circ = self.embed(t.clone());
self.aby.circs.push(circ);
}
}
@@ -550,4 +578,4 @@ pub fn to_aby(ir: Computation) -> ABY {
converter.init_inputs();
converter.aby
}
}

View File

@@ -2,6 +2,7 @@
#include "../../../abycore/circuit/booleancircuits.h"
#include "../../../abycore/circuit/arithmeticcircuits.h"
#include "../../../abycore/circuit/circuit.h"
#include "../../../../../../EZPC/ezpc.h"
#include "../../../abycore/sharing/sharing.h"
@@ -14,15 +15,13 @@ int32_t test_{fn}_circuit(std::map<std::string, std::string> params, e_role role
Circuit* acirc = sharings[S_ARITH]->GetCircuitBuildRoutine();
Circuit* bcirc = sharings[S_BOOL]->GetCircuitBuildRoutine();
Circuit* ycirc = sharings[S_YAO]->GetCircuitBuildRoutine();
output_queue out_q;
// compiled circuit
{circ}
party->ExecCircuit();
// output
{output}
flush_output_queue(out_q, role, bitlen);
delete party;
return 0;
}

202
third_party/EZPC/ezpc.h vendored Normal file
View File

@@ -0,0 +1,202 @@
/*
Authors: Aseem Rastogi, Nishant Kumar, Mayank Rathee.
Copyright:
Copyright (c) 2020 Microsoft Research
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef __EZPC_H_
#define __EZPC_H_
#include "../ABY/src/abycore/circuit/booleancircuits.h"
#include "../ABY/src/abycore/sharing/sharing.h"
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
/*
* somehow we need this redirection for adding Cons gates
* directly calling PutConsGate gives an error
*/
share* put_cons32_gate(Circuit* c, uint32_t val) {
uint32_t x = val;
return c->PutCONSGate(x, (uint32_t)32);
}
share* put_cons64_gate(Circuit* c, uint64_t val) {
uint64_t x = val;
return c->PutCONSGate(x, (uint32_t)64);
}
share* put_cons1_gate(Circuit* c, uint64_t val) {
uint64_t x = val;
return c->PutCONSGate(x, (uint32_t)1);
}
share* left_shift(Circuit* c, share* val, uint32_t shift_factor) {
uint32_t share_wire_count = val->get_bitlength();
share* fresh_zero_share = put_cons32_gate(c, 0);
std::vector<uint32_t> val_wires = val->get_wires();
if(share_wire_count == 1){
cout<<"Error. Share not padded. A share cannot exist with just 1 wire.\n";
}
// Note here the assumption is that if we receive the val share as a share of size 32, we output the share as a share of size 32 only and drop the MSBs which overflow the 32 bit constraint.
for(int i=0; i+shift_factor<share_wire_count; i++){
fresh_zero_share->set_wire_id(shift_factor+i, val_wires[i]);
}
return fresh_zero_share;
}
share* get_zero_share(Circuit* c, int bitlen){
if (bitlen == 32)
return put_cons32_gate(c, 0);
else
return put_cons64_gate(c, 0);
}
share* logical_right_shift(Circuit* c, share* val, uint32_t shift_factor) {
int bitlen = val->get_bitlength();
vector<uint32_t> val_wires = val->get_wires();
vector<uint32_t> zero_share_wires = (get_zero_share(c, bitlen))->get_wires();
vector<uint32_t> new_val_wires(bitlen, 0);
for(int i=0; i<bitlen; i++){
if (i >= (bitlen - shift_factor)){
new_val_wires[i] = zero_share_wires[i];
}
else{
new_val_wires[i] = val_wires[i+shift_factor];
}
}
share* x = create_new_share(new_val_wires, c);
return x;
}
share* arithmetic_right_shift(Circuit* c, share* val, uint32_t shift_factor) {
int bitlen = val->get_bitlength();
share* neg_val = c->PutSUBGate(get_zero_share(c, bitlen), val);
share* is_pos = c->PutGTGate(neg_val, val);
val = c->PutMUXGate(val, neg_val, is_pos);
share* x = logical_right_shift(c, val, shift_factor);
return c->PutMUXGate(x, c->PutSUBGate(get_zero_share(c, bitlen), x), is_pos);
}
/*
* we maintain a queue of outputs
* basically every OUTPUT adds an OUTGate,
* and adds the returned share to this queue
* this queue is then flushed at the end after we have done exec
*/
struct output_queue_elmt {
ostream& os; //output stream to which we will output (cout or files), can this be a reference to prevent copying?
e_role role; //who should we output the clear value to
enum {PrintMsg, PrintValue } kind;
string msg;
share *ptr;
};
typedef vector<output_queue_elmt> output_queue;
/*
* called from the EzPC generated code
*/
void add_to_output_queue(output_queue &q,
share *ptr,
e_role role,
ostream &os)
{
struct output_queue_elmt elmt { os, role, output_queue_elmt::PrintValue, "", ptr };
q.push_back(elmt);
}
void add_print_msg_to_output_queue (output_queue &q, string msg, e_role role, ostream &os)
{
struct output_queue_elmt elmt { os, role, output_queue_elmt::PrintMsg, msg, NULL };
q.push_back(elmt);
}
/*
* flush the queue
* both parties call this function with their role
* called from the EzPC generated code
*/
void flush_output_queue(output_queue &q, e_role role, uint32_t bitlen)
{
for(output_queue::iterator it = q.begin(); it != q.end(); ++it) { //iterate over the queue
if (it->kind == output_queue_elmt::PrintValue) {
if(it->role == ALL || it->role == role) { //if the queue element role is same as mine
if(bitlen == 32) { //output to the stream
it->os << it->ptr->get_clear_value<uint32_t>() << endl;
} else {
it->os << it->ptr->get_clear_value<uint64_t>() << endl;
}
}
} else {
if(it->role == ALL || it->role == role) { //if the queue element role is same as mine
it->os << it->msg << endl;
}
}
}
}
/*
* function to write a single share
* called from EzPC generated code
*
* TODO: confused about bitlen
*/
void write_share(share *ptr, Circuit *circ, uint32_t bitlen, e_role role,
ofstream &of_add,
ofstream &of_rand,
output_queue &q)
{
/* input shares of a random value, SERVER handles rand, CLIENT handles added shares */
share *rand_sh = role == SERVER ? circ->PutINGate((uint32_t)rand(), bitlen, SERVER) : circ->PutDummyINGate(bitlen);
/* add the input share with the random share */
share *add_sh = circ->PutADDGate(ptr, rand_sh);
/* add to the output q, so that it gets written out */
add_to_output_queue(q, circ->PutOUTGate(rand_sh, SERVER), SERVER, of_rand);
add_to_output_queue(q, circ->PutOUTGate(add_sh, CLIENT), CLIENT, of_add);
/* TODO: can we optimize OUTPUT gates for the random value, since we already have its clear value in hand? */
return;
}
template<typename T>
share *read_share(Circuit *circ, e_role role, uint32_t bitlen,
ifstream &if_add,
ifstream &if_rand)
{
/*
* Variables for reading the added value and the random value
*/
T add_val;
T rand_val;
if(role == SERVER) { if_rand >> rand_val; }
if(role == CLIENT) { if_add >> add_val; }
share *add_sh = role == SERVER ? circ->PutDummyINGate(bitlen) : circ->PutINGate(add_val, bitlen, CLIENT);
share *rand_sh = role == SERVER ? circ->PutINGate(rand_val, bitlen, SERVER) : circ->PutDummyINGate(bitlen);
return circ->PutSUBGate(add_sh, rand_sh);
}
#endif