Skip to content

Instantly share code, notes, and snippets.

@timmyjose
Last active September 30, 2023 15:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timmyjose/c913fee7e11f2d90bb31864a05776a71 to your computer and use it in GitHub Desktop.
Save timmyjose/c913fee7e11f2d90bb31864a05776a71 to your computer and use it in GitHub Desktop.
[package]
name = "bubble-sort"
version = "0.1.0"
edition = "2021"
[dependencies]
common = { path = "../common" }
serde_json = { version = "1.0.107", features = ["arbitrary_precision" ]}
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(())
}
[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"] }
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(())
}
$ 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