mirror of
https://github.com/Sunscreen-tech/Sunscreen.git
synced 2026-04-19 03:00:06 -04:00
WIP
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -134,6 +134,12 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.1"
|
||||
@@ -565,6 +571,7 @@ dependencies = [
|
||||
name = "sunscreen_compiler_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_json",
|
||||
|
||||
@@ -9,9 +9,8 @@ use sunscreen_runtime::PrivateRuntime;
|
||||
* the result. Circuits may take any number of parameters and return either a single result
|
||||
* or a tuple of results.
|
||||
*
|
||||
* Currently, the Unsigned type is the only legal type in circuit parameters and return values,
|
||||
* which serves as a placeholder that allows the compiler to build up the circuit. Don't attach
|
||||
* much meaning to it in its current form; this example in fact uses unsigned values!
|
||||
* The unsigned type refers to an unsigned integer modulo the plaintext
|
||||
* modulus (p). p is passed to the compiler via plain_modulus_constraint.
|
||||
*
|
||||
* One takes a circuit and passes them to the compiler, which transforms it into a form
|
||||
* suitable for execution.
|
||||
@@ -63,17 +62,31 @@ fn main() {
|
||||
let (public, secret) = runtime.generate_keys().unwrap();
|
||||
|
||||
/*
|
||||
* Encrypt the values 15 and 5, which matches the circuits interface.
|
||||
* Our circuit accepts 2 `Unsigned` types and adds them together.
|
||||
* The encrypt macro takes a runtime and public key as its first 2
|
||||
* arguments to faciliation encryption, and the remaining arguments
|
||||
* are the actual arguments to the circuit. This macro is variadic;
|
||||
* circuits that take more arguments require more parameters.
|
||||
*/
|
||||
let args = encrypt!(runtime, &public, Unsigned::from(15), Unsigned::from(5)).unwrap();
|
||||
|
||||
/*
|
||||
* Run the circuit with our arguments. This produces a results
|
||||
* bundle containing the encrypted outputs of the circuit.
|
||||
*/
|
||||
let mut results = runtime
|
||||
.run(&circuit, args)
|
||||
.unwrap();
|
||||
|
||||
/*
|
||||
* Our circuit produces a single output rather than a tuple, so the resulting Vec should contain
|
||||
* exactly one value.
|
||||
* Our circuit produces a single `Unsigned` output. The decrypt
|
||||
* macro takes a runtime, secret key, and results bundle as the
|
||||
* first three arguments. The macro is variadic and the remaining
|
||||
* arguments are the types of the circuit's outputs.
|
||||
*
|
||||
* The decrypt macro validates the types we pass match the
|
||||
* circuit's return types. We need to pass these so types so
|
||||
* the compiler can ensure the return type is known at compile time.
|
||||
*/
|
||||
let c = decrypt!(runtime, &secret, results, Unsigned).unwrap();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ proc-macro = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
convert_case = "0.4.0"
|
||||
proc-macro2 = "1.0.32"
|
||||
quote = "1.0.10"
|
||||
syn = { version = "1.0.81", features = ["derive", "full", "fold"] }
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::internals::{attr::Attrs, case::Scheme};
|
||||
use convert_case::{Case, Casing};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{
|
||||
parse_macro_input, spanned::Spanned, FnArg, Ident, Index, ItemFn, Pat, ReturnType, Type,
|
||||
parse_macro_input, spanned::Spanned, FnArg, Ident, Index, ItemFn, Pat, ReturnType, Type, punctuated::Punctuated, Token
|
||||
};
|
||||
|
||||
pub fn circuit_impl(
|
||||
@@ -87,47 +88,9 @@ pub fn circuit_impl(
|
||||
}
|
||||
});
|
||||
|
||||
let capture_outputs = match ret {
|
||||
ReturnType::Type(_, t) => {
|
||||
let tuple_inners = match &**t {
|
||||
Type::Tuple(t) => t.elems.iter().map(|x| &*x).collect::<Vec<&Type>>(),
|
||||
Type::Paren(t) => {
|
||||
vec![&*t.elem]
|
||||
}
|
||||
Type::Path(_) => {
|
||||
vec![&**t]
|
||||
}
|
||||
_ => {
|
||||
return proc_macro::TokenStream::from(quote! {
|
||||
compile_error!("Circuits must return a single Cipthertext or a tuple of Ciphertexts");
|
||||
});
|
||||
}
|
||||
};
|
||||
let catpured_outputs = capture_outputs(ret);
|
||||
|
||||
if tuple_inners.len() == 1 {
|
||||
quote_spanned! {tuple_inners[0].span() =>
|
||||
v.output();
|
||||
}
|
||||
} else {
|
||||
tuple_inners
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, t)| {
|
||||
let index = Index::from(i);
|
||||
|
||||
quote_spanned! {t.span() =>
|
||||
v.#index.output();
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
ReturnType::Default => {
|
||||
quote! {}
|
||||
}
|
||||
};
|
||||
|
||||
let foo = proc_macro::TokenStream::from(quote! {
|
||||
proc_macro::TokenStream::from(quote! {
|
||||
#(#attrs)*
|
||||
#vis fn #circuit_name() -> (
|
||||
sunscreen_compiler::SchemeType,
|
||||
@@ -163,7 +126,7 @@ pub fn circuit_impl(
|
||||
});
|
||||
|
||||
match panic_res {
|
||||
Ok(v) => { #capture_outputs },
|
||||
Ok(v) => { #catpured_outputs },
|
||||
Err(err) => {
|
||||
ctx.swap(&RefCell::new(None));
|
||||
std::panic::resume_unwind(err)
|
||||
@@ -180,11 +143,82 @@ pub fn circuit_impl(
|
||||
|
||||
(#scheme_type, circuit_builder, signature)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn emit_encoder(
|
||||
circuit_name: &str,
|
||||
inputs: &[(&syn::PatType, &proc_macro2::Ident)],
|
||||
ret: &ReturnType
|
||||
) -> TokenStream {
|
||||
let struct_name = Ident::new(&format!("{}Interface", circuit_name.to_case(Case::Pascal)), Span::call_site());
|
||||
|
||||
let arguments = inputs.iter().map(|(t, ident)| {
|
||||
quote_spanned! { t.span()=>
|
||||
.arg(#ident)
|
||||
}
|
||||
});
|
||||
|
||||
// panic!("{}", foo);
|
||||
let fn_args = inputs.iter().map(|(t, _)| {
|
||||
quote! {
|
||||
#t,
|
||||
}
|
||||
}).collect::<Vec<TokenStream>>();
|
||||
|
||||
foo
|
||||
quote! {
|
||||
pub struct #struct_name;
|
||||
|
||||
impl #struct_name {
|
||||
fn args(#(#fn_args)*) -> sunscreen_compiler::Arguments {
|
||||
sunscreen_compiler::Arguments::new()
|
||||
#(#arguments)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn capture_outputs(ret: &ReturnType) -> TokenStream {
|
||||
match ret {
|
||||
ReturnType::Type(_, t) => {
|
||||
let tuple_inners = match &**t {
|
||||
Type::Tuple(t) => t.elems.iter().map(|x| &*x).collect::<Vec<&Type>>(),
|
||||
Type::Paren(t) => {
|
||||
vec![&*t.elem]
|
||||
}
|
||||
Type::Path(_) => {
|
||||
vec![&**t]
|
||||
}
|
||||
_ => {
|
||||
return TokenStream::from(quote! {
|
||||
compile_error!("Circuits must return a single Cipthertext or a tuple of Ciphertexts");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if tuple_inners.len() == 1 {
|
||||
quote_spanned! {tuple_inners[0].span() =>
|
||||
v.output();
|
||||
}
|
||||
} else {
|
||||
tuple_inners
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, t)| {
|
||||
let index = Index::from(i);
|
||||
|
||||
quote_spanned! {t.span() =>
|
||||
v.#index.output();
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
ReturnType::Default => {
|
||||
quote! {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_signature(args: &[&Type], ret: &ReturnType) -> TokenStream {
|
||||
|
||||
@@ -11,6 +11,7 @@ use std::collections::HashMap;
|
||||
|
||||
pub struct Attrs {
|
||||
pub scheme: Scheme,
|
||||
pub interface_file: Option<String>
|
||||
}
|
||||
|
||||
impl Parse for Attrs {
|
||||
@@ -82,10 +83,16 @@ impl Parse for Attrs {
|
||||
"`scheme` requires a value".to_owned(),
|
||||
))?;
|
||||
|
||||
let interface_file = attrs
|
||||
.get("interface_file")
|
||||
.map(|s| s.to_owned())
|
||||
.unwrap_or(None);
|
||||
|
||||
Ok(Self {
|
||||
scheme: Scheme::parse(&scheme_type).map_err(|_e| {
|
||||
Error::new_spanned(vars, format!("Unknown variant {}", &scheme_type))
|
||||
})?,
|
||||
interface_file: interface_file,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,4 @@ pub struct InputBundle {
|
||||
/**
|
||||
* The encrypted result of running a circuit.
|
||||
*/
|
||||
pub struct OutputBundle(pub Vec<Ciphertext>);
|
||||
pub struct OutputBundle(pub Vec<Ciphertext>);
|
||||
@@ -18,8 +18,8 @@ enum Context {
|
||||
}
|
||||
|
||||
/**
|
||||
* A private runtime is one that can perform operations that require either a public or
|
||||
* secret key.
|
||||
* A private runtime is one that can perform both operations that require
|
||||
* a secret key and operations that require a public key.
|
||||
*/
|
||||
pub struct PrivateRuntime {
|
||||
public_runtime: PublicRuntime,
|
||||
|
||||
Reference in New Issue
Block a user