mirror of
https://github.com/Sunscreen-tech/Sunscreen.git
synced 2026-04-19 03:00:06 -04:00
Use ?
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use sunscreen::{
|
||||
fhe_program,
|
||||
types::{bfv::Rational, Cipher},
|
||||
Ciphertext, CompiledFheProgram, Compiler, Params, PrivateKey, PublicKey,
|
||||
Ciphertext, CompiledFheProgram, Compiler, Params, PrivateKey,
|
||||
Error,
|
||||
PublicKey,
|
||||
Runtime,
|
||||
};
|
||||
use std::time::Instant;
|
||||
|
||||
#[fhe_program(scheme = "bfv")]
|
||||
/// This program swaps NU tokens to receive ETH.
|
||||
@@ -30,25 +31,25 @@ struct Miner {
|
||||
}
|
||||
|
||||
impl Miner {
|
||||
pub fn setup() -> Miner {
|
||||
let swap_fhe = Compiler::with_fhe_program(swap_nu).compile().unwrap();
|
||||
pub fn setup() -> Result<Miner, Error> {
|
||||
let swap_fhe = Compiler::with_fhe_program(swap_nu).compile()?;
|
||||
|
||||
let runtime = Runtime::new(&swap_fhe.metadata.params).unwrap();
|
||||
let runtime = Runtime::new(&swap_fhe.metadata.params)?;
|
||||
|
||||
Miner {
|
||||
Ok(Miner {
|
||||
swap_fhe,
|
||||
runtime,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run_contract(
|
||||
&self,
|
||||
nu_tokens_to_trade: Ciphertext,
|
||||
public_key: &PublicKey,
|
||||
) -> Ciphertext {
|
||||
let results = self.runtime.run(&self.swap_fhe, vec![nu_tokens_to_trade], public_key).unwrap();
|
||||
) -> Result<Ciphertext, Error> {
|
||||
let results = self.runtime.run(&self.swap_fhe, vec![nu_tokens_to_trade], public_key)?;
|
||||
|
||||
results[0].clone()
|
||||
Ok(results[0].clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,50 +66,51 @@ struct Alice {
|
||||
}
|
||||
|
||||
impl Alice {
|
||||
pub fn setup(params: &Params) -> Alice {
|
||||
let runtime = Runtime::new(params).unwrap();
|
||||
pub fn setup(params: &Params) -> Result<Alice, Error> {
|
||||
let runtime = Runtime::new(params)?;
|
||||
|
||||
let (public_key, private_key) = runtime.generate_keys().unwrap();
|
||||
let (public_key, private_key) = runtime.generate_keys()?;
|
||||
|
||||
Alice {
|
||||
Ok(Alice {
|
||||
public_key,
|
||||
private_key,
|
||||
runtime,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_transaction(&self, amount: f64) -> Ciphertext {
|
||||
self.runtime
|
||||
.encrypt(Rational::try_from(amount).unwrap(), &self.public_key)
|
||||
.unwrap()
|
||||
pub fn create_transaction(&self, amount: f64) -> Result<Ciphertext, Error> {
|
||||
Ok(self.runtime
|
||||
.encrypt(Rational::try_from(amount)?, &self.public_key)?
|
||||
)
|
||||
}
|
||||
|
||||
pub fn check_received_eth(&self, received_eth: Ciphertext) {
|
||||
pub fn check_received_eth(&self, received_eth: Ciphertext) -> Result<(), Error> {
|
||||
let received_eth: Rational = self
|
||||
.runtime
|
||||
.decrypt(&received_eth, &self.private_key)
|
||||
.unwrap();
|
||||
.decrypt(&received_eth, &self.private_key)?;
|
||||
|
||||
let received_eth: f64 = received_eth.into();
|
||||
|
||||
println!("Alice received {}ETH", received_eth);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let comp_time = Instant::now();
|
||||
fn main() -> Result<(), Error> {
|
||||
// Set up the miner with some NU and ETH tokens.
|
||||
let miner = Miner::setup();
|
||||
println!("{}", comp_time.elapsed().as_secs_f64());
|
||||
let miner = Miner::setup()?;
|
||||
|
||||
let run_time = Instant::now();
|
||||
// Alice sets herself up. The FHE scheme parameters are public to the
|
||||
// protocol, so Alice has them.
|
||||
let alice = Alice::setup(&miner.swap_fhe.metadata.params);
|
||||
let alice = Alice::setup(&miner.swap_fhe.metadata.params)?;
|
||||
|
||||
let transaction = alice.create_transaction(20.0)?;
|
||||
|
||||
let encrypted_received_eth =
|
||||
miner.run_contract(alice.create_transaction(20.0), &alice.public_key);
|
||||
miner.run_contract(transaction, &alice.public_key)?;
|
||||
|
||||
println!("{}", run_time.elapsed().as_secs_f64());
|
||||
alice.check_received_eth(encrypted_received_eth);
|
||||
alice.check_received_eth(encrypted_received_eth)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#[derive(Debug)]
|
||||
/// Represents any error that can happen in our app. This is the built-in
|
||||
/// canonical way to do error handling in Rust, but there are better solutions
|
||||
/// with less boilerplate. E.g. the [quick_error](https://docs.rs/quick-error/2.0.1/quick_error/)
|
||||
/// and [anyhow](https://docs.rs/anyhow/latest/anyhow/index.html) crates.
|
||||
pub enum Error {
|
||||
SunscreenError(sunscreen::Error),
|
||||
|
||||
SendError,
|
||||
|
||||
RecvError,
|
||||
|
||||
IoError(std::io::Error),
|
||||
|
||||
ParseError,
|
||||
}
|
||||
|
||||
/// Converts a sunscreen::Error into an Error. Needed to use `?` operator.
|
||||
impl From<sunscreen::Error> for Error {
|
||||
fn from(err: sunscreen::Error) -> Self {
|
||||
Self::SunscreenError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sunscreen::RuntimeError> for Error {
|
||||
fn from(err: sunscreen::RuntimeError) -> Self {
|
||||
Self::SunscreenError(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl <T> From<std::sync::mpsc::SendError<T>> for Error {
|
||||
fn from(_: std::sync::mpsc::SendError<T>) -> Error {
|
||||
Self::SendError
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::sync::mpsc::RecvError> for Error {
|
||||
fn from(_: std::sync::mpsc::RecvError) -> Error {
|
||||
Self::RecvError
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Error {
|
||||
Self::IoError(err)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
mod error;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::thread::{self, JoinHandle};
|
||||
@@ -10,8 +8,6 @@ use sunscreen::{
|
||||
RuntimeError,
|
||||
};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
fn help() {
|
||||
println!("This is a privacy preserving calculator. You can add, subtract, multiply, divide decimal values. The operation is sent to Bob in cleartext while the operands
|
||||
are encrypted. Bob chooses an FHE program corresponding to the selected operation and computes the result. Additionally, Bob saves the last computed value as `ans`, which you may use as either operand.");
|
||||
@@ -50,6 +46,10 @@ enum ParseResult {
|
||||
Expression(Expression),
|
||||
}
|
||||
|
||||
enum Error {
|
||||
ParseError,
|
||||
}
|
||||
|
||||
fn parse_input(line: &str) -> Result<ParseResult, Error> {
|
||||
if line == "help" {
|
||||
return Ok(ParseResult::Help);
|
||||
@@ -96,13 +96,14 @@ fn parse_input(line: &str) -> Result<ParseResult, Error> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn encrypt_term(runtime: &Runtime, public_key: &PublicKey, input: Term) -> Result<Term, Error> {
|
||||
fn encrypt_term(runtime: &Runtime, public_key: &PublicKey, input: Term) -> Term {
|
||||
match input {
|
||||
Term::Ans => Ok(Term::Ans),
|
||||
Term::F64(v) => Ok(Term::Encrypted(
|
||||
Term::Ans => Term::Ans,
|
||||
Term::F64(v) => Term::Encrypted(
|
||||
runtime
|
||||
.encrypt(Rational::try_from(v)?, &public_key)?,
|
||||
)),
|
||||
.encrypt(Rational::try_from(v).unwrap(), &public_key)
|
||||
.unwrap(),
|
||||
),
|
||||
_ => {
|
||||
panic!("This shouldn't happen.");
|
||||
}
|
||||
@@ -116,88 +117,82 @@ fn alice(
|
||||
recv_res: Receiver<Ciphertext>,
|
||||
) -> JoinHandle<()> {
|
||||
thread::spawn(move || {
|
||||
let thread_body = move || -> Result<(), Error> {
|
||||
let stdin = io::stdin();
|
||||
let mut stdout = io::stdout();
|
||||
let stdin = io::stdin();
|
||||
let mut stdout = io::stdout();
|
||||
|
||||
println!("Bob's private calculator. Type `help` for help.");
|
||||
println!("Bob's private calculator. Type `help` for help.");
|
||||
|
||||
// Bob needs to send us the scheme parameters compatible with his FHE program.
|
||||
let params = recv_params.recv()?;
|
||||
// Bob needs to send us the scheme parameters compatible with his FHE program.
|
||||
let params = recv_params.recv().unwrap();
|
||||
|
||||
let runtime = Runtime::new(¶ms)?;
|
||||
let runtime = Runtime::new(¶ms).unwrap();
|
||||
|
||||
let (public_key, private_key) = runtime.generate_keys()?;
|
||||
let (public_key, private_key) = runtime.generate_keys().unwrap();
|
||||
|
||||
// Send Bob a copy of our public keys.
|
||||
send_pub.send(public_key.clone())?;
|
||||
// Send Bob a copy of our public keys.
|
||||
send_pub.send(public_key.clone()).unwrap();
|
||||
|
||||
loop {
|
||||
print!(">> ");
|
||||
loop {
|
||||
print!(">> ");
|
||||
|
||||
stdout.flush()?;
|
||||
stdout.flush().unwrap();
|
||||
|
||||
let mut line = String::new();
|
||||
stdin.read_line(&mut line)?;
|
||||
let line = line.trim();
|
||||
let mut line = String::new();
|
||||
stdin.read_line(&mut line).unwrap();
|
||||
let line = line.trim();
|
||||
|
||||
// Read the line and parse it into operands and an operator.
|
||||
let parsed = parse_input(&line);
|
||||
// Read the line and parse it into operands and an operator.
|
||||
let parsed = parse_input(&line);
|
||||
|
||||
let Expression { left, right, op } = match parsed {
|
||||
Ok(ParseResult::Expression(val)) => val,
|
||||
Ok(ParseResult::Exit) => std::process::exit(0),
|
||||
Ok(ParseResult::Help) => {
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Parse error. Try again.");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let Expression { left, right, op } = match parsed {
|
||||
Ok(ParseResult::Expression(val)) => val,
|
||||
Ok(ParseResult::Exit) => std::process::exit(0),
|
||||
Ok(ParseResult::Help) => {
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Parse error. Try again.");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Encrypt the left and right terms.
|
||||
let encrypt_left = encrypt_term(&runtime, &public_key, left)?;
|
||||
let encrypt_right = encrypt_term(&runtime, &public_key, right)?;
|
||||
// Encrypt the left and right terms.
|
||||
let encrypt_left = encrypt_term(&runtime, &public_key, left);
|
||||
let encrypt_right = encrypt_term(&runtime, &public_key, right);
|
||||
|
||||
// Send Bob our encrypted operation.
|
||||
send_calc
|
||||
.send(Expression {
|
||||
left: encrypt_left,
|
||||
right: encrypt_right,
|
||||
op: op,
|
||||
})?;
|
||||
// Send Bob our encrypted operation.
|
||||
send_calc
|
||||
.send(Expression {
|
||||
left: encrypt_left,
|
||||
right: encrypt_right,
|
||||
op: op,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Get our result from Bob and print it.
|
||||
let result: Ciphertext = recv_res.recv()?;
|
||||
let result: Rational = match runtime.decrypt(&result, &private_key) {
|
||||
Ok(v) => v,
|
||||
Err(RuntimeError::TooMuchNoise) => {
|
||||
println!("Decryption failed: too much noise");
|
||||
continue;
|
||||
}
|
||||
Err(e) => { return Err(e.into()); },
|
||||
};
|
||||
let result: f64 = result.into();
|
||||
// Get our result from Bob and print it.
|
||||
let result: Ciphertext = recv_res.recv().unwrap();
|
||||
let result: Rational = match runtime.decrypt(&result, &private_key) {
|
||||
Ok(v) => v,
|
||||
Err(RuntimeError::TooMuchNoise) => {
|
||||
println!("Decryption failed: too much noise");
|
||||
continue;
|
||||
}
|
||||
Err(e) => panic!("{:#?}", e),
|
||||
};
|
||||
let result: f64 = result.into();
|
||||
|
||||
println!("{}", result);
|
||||
}
|
||||
};
|
||||
|
||||
match thread_body() {
|
||||
Ok(_) => {},
|
||||
Err(e) => panic!("{:#?}", e),
|
||||
println!("{}", result);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn compile_fhe_programs() -> Result<(
|
||||
fn compile_fhe_programs() -> (
|
||||
CompiledFheProgram,
|
||||
CompiledFheProgram,
|
||||
CompiledFheProgram,
|
||||
CompiledFheProgram,
|
||||
), Error> {
|
||||
) {
|
||||
#[fhe_program(scheme = "bfv")]
|
||||
fn add(a: Cipher<Rational>, b: Cipher<Rational>) -> Cipher<Rational> {
|
||||
a + b
|
||||
@@ -228,24 +223,24 @@ fn compile_fhe_programs() -> Result<(
|
||||
.additional_noise_budget(32)
|
||||
.plain_modulus_constraint(PlainModulusConstraint::Raw(1_000_000))
|
||||
.compile()
|
||||
?;
|
||||
.unwrap();
|
||||
|
||||
let mul_program = Compiler::with_fhe_program(mul)
|
||||
.with_params(&add_program.metadata.params)
|
||||
.compile()
|
||||
?;
|
||||
.unwrap();
|
||||
|
||||
let div_program = Compiler::with_fhe_program(div)
|
||||
.with_params(&add_program.metadata.params)
|
||||
.compile()
|
||||
?;
|
||||
.unwrap();
|
||||
|
||||
let sub_program = Compiler::with_fhe_program(sub)
|
||||
.with_params(&add_program.metadata.params)
|
||||
.compile()
|
||||
?;
|
||||
.unwrap();
|
||||
|
||||
Ok((add_program, sub_program, mul_program, div_program))
|
||||
(add_program, sub_program, mul_program, div_program)
|
||||
}
|
||||
|
||||
fn bob(
|
||||
@@ -255,58 +250,50 @@ fn bob(
|
||||
send_res: Sender<Ciphertext>,
|
||||
) -> JoinHandle<()> {
|
||||
thread::spawn(move || {
|
||||
let thread_body = move || -> Result<(), Error> {
|
||||
let (add, sub, mul, div) = compile_fhe_programs()?;
|
||||
let (add, sub, mul, div) = compile_fhe_programs();
|
||||
|
||||
send_params.send(add.metadata.params.clone())?;
|
||||
send_params.send(add.metadata.params.clone()).unwrap();
|
||||
|
||||
let public_key = recv_pub.recv()?;
|
||||
let public_key = recv_pub.recv().unwrap();
|
||||
|
||||
let runtime = Runtime::new(&add.metadata.params)?;
|
||||
let runtime = Runtime::new(&add.metadata.params).unwrap();
|
||||
|
||||
let mut ans = runtime
|
||||
.encrypt(Rational::try_from(0f64)?, &public_key)
|
||||
?;
|
||||
let mut ans = runtime
|
||||
.encrypt(Rational::try_from(0f64).unwrap(), &public_key)
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
let Expression { left, right, op } = recv_calc.recv()?;
|
||||
loop {
|
||||
let Expression { left, right, op } = recv_calc.recv().unwrap();
|
||||
|
||||
let left = match left {
|
||||
Term::Ans => ans.clone(),
|
||||
Term::Encrypted(c) => c,
|
||||
_ => panic!("Alice sent us a plaintext!"),
|
||||
};
|
||||
let left = match left {
|
||||
Term::Ans => ans.clone(),
|
||||
Term::Encrypted(c) => c,
|
||||
_ => panic!("Alice sent us a plaintext!"),
|
||||
};
|
||||
|
||||
let right = match right {
|
||||
Term::Ans => ans.clone(),
|
||||
Term::Encrypted(c) => c,
|
||||
_ => panic!("Alice sent us a plaintext!"),
|
||||
};
|
||||
let right = match right {
|
||||
Term::Ans => ans.clone(),
|
||||
Term::Encrypted(c) => c,
|
||||
_ => panic!("Alice sent us a plaintext!"),
|
||||
};
|
||||
|
||||
let mut c = match op {
|
||||
Operand::Add => runtime.run(&add, vec![left, right], &public_key)?,
|
||||
Operand::Sub => runtime.run(&sub, vec![left, right], &public_key)?,
|
||||
Operand::Mul => runtime.run(&mul, vec![left, right], &public_key)?,
|
||||
Operand::Div => runtime.run(&div, vec![left, right], &public_key)?,
|
||||
};
|
||||
let mut c = match op {
|
||||
Operand::Add => runtime.run(&add, vec![left, right], &public_key).unwrap(),
|
||||
Operand::Sub => runtime.run(&sub, vec![left, right], &public_key).unwrap(),
|
||||
Operand::Mul => runtime.run(&mul, vec![left, right], &public_key).unwrap(),
|
||||
Operand::Div => runtime.run(&div, vec![left, right], &public_key).unwrap(),
|
||||
};
|
||||
|
||||
// Our FHE program produces a single value, so move the value out of the vector.
|
||||
let c = c.drain(0..).next().expect("Internal error: FHE program didn't produce a result");
|
||||
ans = c.clone();
|
||||
// Our FHE program produces a single value, so move the value out of the vector.
|
||||
let c = c.drain(0..).next().unwrap();
|
||||
ans = c.clone();
|
||||
|
||||
send_res.send(c)?;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
match thread_body() {
|
||||
Ok(_) => {},
|
||||
Err(e) => panic!("{:#?}", e),
|
||||
};
|
||||
send_res.send(c).unwrap();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
fn main() {
|
||||
// A channel for Alice to send her public keys to Bob.
|
||||
let (send_alice_pub, receive_alice_pub) = std::sync::mpsc::channel::<PublicKey>();
|
||||
|
||||
@@ -337,6 +324,4 @@ fn main() -> Result<(), Error> {
|
||||
|
||||
a.join().unwrap();
|
||||
b.join().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -227,15 +227,15 @@ where
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let n_0 = 1 << 31 - 1;
|
||||
let n_1 = 1 << 31 - 1;
|
||||
let n_2 = 1 << 31 - 1;
|
||||
let n_0 = 2;
|
||||
let n_1 = 7;
|
||||
let n_2 = 9;
|
||||
|
||||
env_logger::init();
|
||||
|
||||
// Signed types allow us to use a really small modulus,
|
||||
// allowing us to get very performant parameters.
|
||||
let plain_modulus = PlainModulusConstraint::Raw(200);
|
||||
let plain_modulus = PlainModulusConstraint::Raw(64);
|
||||
|
||||
println!("**********Naive**************");
|
||||
println!("\t**********Native************");
|
||||
|
||||
@@ -38,8 +38,10 @@ fn main() -> Result<(), Error> {
|
||||
* Sunscreen allows experts to explicitly set the scheme parameters, but the default behavior
|
||||
* is to let the compiler run your FHE program a number of times with different parameters and measure
|
||||
* the resulting noise.
|
||||
|
||||
* Afterwards, we simply compile and assert the compilation succeeds by calling unwrap. Compilation
|
||||
*
|
||||
* Afterwards, we simply compile. The `?` operator is Rust's standard
|
||||
* error handling mechanism; the current function (`main`)
|
||||
* returns when an error occurs or continues on success. Compilation
|
||||
* returns the compiled FHE program and parameters.
|
||||
*/
|
||||
let fhe_program = Compiler::with_fhe_program(simple_multiply)
|
||||
|
||||
Reference in New Issue
Block a user