Last active
September 30, 2023 15:53
-
-
Save timmyjose/c913fee7e11f2d90bb31864a05776a71 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "bubble-sort" | |
version = "0.1.0" | |
edition = "2021" | |
[dependencies] | |
common = { path = "../common" } | |
serde_json = { version = "1.0.107", features = ["arbitrary_precision" ]} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use common::{compile_contract, run_contract, Args, Ctx}; | |
use serde_json::json; | |
use std::collections::HashMap; | |
fn main() -> Result<(), Box<dyn std::error::Error>> { | |
// specify your cpntract here | |
let contract = r#" | |
@public | |
contract BubbleSort { | |
elements: i32[]; | |
constructor (elements: i32[]) { | |
this.elements = elements; | |
} | |
function sort() { | |
let i: u32 = 0; | |
let j: u32 = 0; | |
let one: u32 = 1; | |
let len = this.elements.length; | |
while (i < len) { | |
while (j < len - i - one) { | |
let right = j + one; | |
if (this.elements[j] > this.elements[right]) { | |
let t = this.elements[j]; | |
this.elements[j] = this.elements[right]; | |
this.elements[right] = t; | |
} | |
j += 1; | |
} | |
i += 1; | |
} | |
} | |
} | |
"#; | |
// pass the name of `contract` here | |
let contract_name = Some("BubbleSort"); | |
// pass the name of the function to be executed here | |
let function_name = "sort".to_string(); | |
// pass the name of the proof file here | |
let proof_file_name = "bubble_sort.proof"; | |
let (miden_code, abi) = compile_contract(contract, contract_name, &function_name)?; | |
let args = Args { | |
advice_tape_json: Some("[1, 2]".into()), | |
this_values: HashMap::new(), | |
this_json: Some(json!({"elements": [1, -1, 2, 3, 5, 6, 7, 9, 10, 5]})), | |
other_records: HashMap::new(), | |
abi, | |
ctx: Ctx::default(), | |
proof_output: Some(proof_file_name.to_string()), | |
}; | |
// Run the contract. In addition to the output (if any), you should see the proof file | |
// generated in the same directpry: `<proof_file_name>.proof`. | |
run_contract(miden_code, args)?; | |
Ok(()) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "common" | |
version = "0.1.0" | |
edition = "2021" | |
[dependencies] | |
polylang= { git = "https://github.com/polybase/polylang" } | |
polylang_parser = { git = "https://github.com/polybase/polylang" } | |
polylang-prover = { git = "https://github.com/polybase/polylang" } | |
abi = { git = "https://github.com/polybase/polylang" } | |
serde_json = { version = "1.0.107", features = ["arbitrary_precision" ]} | |
serde = { version = "1.0.188", features = ["derive"] } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use abi::Abi; | |
use std::{collections::HashMap, io::Write}; | |
#[derive(Default, serde::Deserialize)] | |
#[serde(rename_all = "camelCase")] | |
pub struct Ctx { | |
pub public_key: Option<abi::publickey::Key>, | |
} | |
pub struct Args { | |
pub advice_tape_json: Option<String>, | |
pub this_values: HashMap<String, String>, | |
pub this_json: Option<serde_json::Value>, | |
pub other_records: HashMap<String, Vec<(serde_json::Value, Vec<u32>)>>, | |
pub abi: Abi, | |
pub ctx: Ctx, | |
pub proof_output: Option<String>, | |
} | |
impl Args { | |
pub fn inputs( | |
&self, | |
hasher: impl Fn( | |
abi::Type, | |
&abi::Value, | |
Option<&[u32]>, | |
) -> Result<[u64; 4], Box<dyn std::error::Error>>, | |
) -> Result<polylang_prover::Inputs, Box<dyn std::error::Error>> { | |
let this = self.this_value()?; | |
let abi::Value::StructValue(sv) = &this else { | |
return Err("This value is not a struct".into()); | |
}; | |
let this_fields = match self.abi.this_type.as_ref().unwrap() { | |
abi::Type::Struct(s) => &s.fields, | |
_ => unreachable!(), | |
}; | |
let this_field_hashes = sv | |
.iter() | |
.enumerate() | |
.map(|(i, (_, v))| hasher(this_fields[i].1.clone(), &v, Some(&[0]))) | |
.collect::<Result<Vec<_>, _>>()?; | |
Ok(polylang_prover::Inputs { | |
abi: self.abi.clone(), | |
ctx_public_key: self.ctx.public_key.clone(), | |
this_salts: sv.iter().map(|_| 0).collect(), | |
this: this.try_into()?, | |
this_field_hashes, | |
args: serde_json::from_str( | |
&self | |
.advice_tape_json | |
.as_ref() | |
.map(|x| x.as_str()) | |
.unwrap_or("[]"), | |
)?, | |
other_records: self.other_records.clone(), | |
}) | |
} | |
fn this_value(&self) -> Result<abi::Value, Box<dyn std::error::Error>> { | |
self.this_value_json() | |
} | |
fn this_value_json(&self) -> Result<abi::Value, Box<dyn std::error::Error>> { | |
let Some(this_json) = &self.this_json else { | |
return Err("No JSON value for `this`".into()); | |
}; | |
let this_type = self | |
.abi | |
.this_type | |
.as_ref() | |
.ok_or_else(|| "ABI does not specify a `this` type")?; | |
let abi::Type::Struct(struct_) = this_type else { | |
return Err("This type is not a struct".into()); | |
}; | |
let use_defaults = this_json.as_object().map(|o| o.is_empty()).unwrap_or(false); | |
let mut struct_values = Vec::new(); | |
for (field_name, field_type) in &struct_.fields { | |
let field_value = match this_json.get(field_name) { | |
Some(value) => abi::Parser::parse(field_type, value)?, | |
None if use_defaults => field_type.default_value(), | |
None if matches!(field_type, abi::Type::Nullable(_)) => field_type.default_value(), | |
None => return Err(format!("missing value for field `{}`", field_name).into()), | |
}; | |
struct_values.push((field_name.clone(), field_value)); | |
} | |
Ok(abi::Value::StructValue(struct_values)) | |
} | |
} | |
pub fn compile_contract( | |
contract: &'static str, | |
contract_name: Option<&str>, | |
function_name: &str, | |
) -> Result<(String, abi::Abi), Box<dyn std::error::Error>> { | |
let program = polylang_parser::parse(&contract)?; | |
Ok( | |
polylang::compiler::compile(program, contract_name, &function_name) | |
.map_err(|e| e.add_source(contract)) | |
.unwrap_or_else(|e| panic!("{e}")), | |
) | |
} | |
pub fn run_contract(miden_code: String, mut args: Args) -> Result<(), Box<dyn std::error::Error>> { | |
let has_this_type = if args.abi.this_type.is_none() { | |
args.abi.this_type = Some(abi::Type::Struct(abi::Struct { | |
name: "Empty".to_string(), | |
fields: Vec::new(), | |
})); | |
false | |
} else { | |
true | |
}; | |
let inputs = args.inputs(|t, v, s| Ok(polylang_prover::hash_this(t, v, s)?))?; | |
let program = polylang_prover::compile_program(&args.abi, &miden_code) | |
.map_err(|e| e.add_source(miden_code))?; | |
let (output, prove) = polylang_prover::run(&program, &inputs)?; | |
if has_this_type { | |
println!( | |
"this_json: {}", | |
TryInto::<serde_json::Value>::try_into(output.this(&args.abi)?)? | |
); | |
} | |
if let Some(out) = args.proof_output { | |
let proof = prove()?; | |
let mut file = std::fs::File::create(&out)?; | |
file.write_all(&proof.to_bytes())?; | |
println!("Proof saved to {out}"); | |
} | |
Ok(()) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ cargo run --release -p bubble-sort | |
Compiling bubble-sort v0.1.0 (/Users/z0ltan/work/polybase/polylang-site/examples/bubble-sort) | |
Finished release [optimized] target(s) in 0.79s | |
Running `target/release/bubble-sort` | |
thread 'main' panicked at 'type mismatch: expected map type | |
source `this.elements[j] = this.elements[right];` at line 21:25..64', common/src/lib.rs:107:33 | |
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment