use std::error::Error as StdError;
use std::result::Result as StdResult;
use llzk::{builder::OpBuilder, prelude::*};
type Result<T> = StdResult<T, Box<dyn StdError>>;
const MAIN_STRUCT_NAME: &'static str = "Entry";
fn main() -> Result<()> {
let context = LlzkContext::new();
let location = Location::unknown(&context);
let mut module = llzk_module(location);
module.as_operation_mut().set_attribute(
MAIN_ATTR_NAME.as_ref(),
TypeAttribute::new(
StructType::new(FlatSymbolRefAttribute::new(&context, MAIN_STRUCT_NAME), &[]).into(),
)
.into(),
);
let main_st = dialect::r#struct::def(location, MAIN_STRUCT_NAME, &[], [])?;
let felt_type = FeltType::new(&context);
let out_field = {
let is_column = false;
let is_public = true;
dialect::r#struct::member(location, "c", felt_type, is_column, is_public)?
};
let compute_fn = witness(&context, location, felt_type.into(), &out_field)?;
let constrain_fn = constraints(&context, location, felt_type.into(), &out_field)?;
main_st.body().append_operation(out_field.into());
main_st.body().append_operation(compute_fn.into());
main_st.body().append_operation(constrain_fn.into());
module.body().append_operation(main_st.into());
let module_op = module.as_operation();
if module_op.verify() {
println!("{module_op}")
} else {
eprintln!("Module failed to verify");
}
Ok(())
}
fn witness<'c>(
context: &'c Context,
location: Location<'c>,
input_type: Type<'c>,
out_field: &MemberDefOp<'c>,
) -> Result<Operation<'c>> {
let inputs = vec![(input_type, location); 2];
let pub_attr = [PublicAttribute::new_named_attr(context)];
let main_ty = StructType::from_str(context, MAIN_STRUCT_NAME);
let compute_fn = dialect::r#struct::helpers::compute_fn(
location,
main_ty,
&inputs,
Some(&[pub_attr.to_vec(), pub_attr.to_vec()]),
)?;
let (block, ret_op) = compute_fn
.region(0)?
.first_block()
.and_then(|b| Some((b, b.terminator()?)))
.unwrap();
let a = block.argument(0)?;
let b = block.argument(1)?;
let c = block
.insert_operation_before(ret_op, dialect::felt::div(location, a.into(), b.into())?)
.result(0)?;
let self_value = block.first_operation().unwrap().result(0)?;
block.insert_operation_before(
ret_op,
dialect::r#struct::writem(
location,
self_value.into(),
out_field.member_name(),
c.into(),
)?,
);
Ok(compute_fn.into())
}
fn constraints<'c>(
context: &'c Context,
location: Location<'c>,
input_type: Type<'c>,
out_field: &MemberDefOp<'c>,
) -> Result<Operation<'c>> {
let inputs = vec![(input_type, location); 2];
let pub_attr = [PublicAttribute::new_named_attr(context)];
let main_ty = StructType::from_str(context, MAIN_STRUCT_NAME);
let constrain_fn = dialect::r#struct::helpers::constrain_fn(
location,
main_ty,
&inputs,
Some(&[pub_attr.to_vec(), pub_attr.to_vec()]),
)?;
let (block, ret_op) = constrain_fn
.region(0)?
.first_block()
.and_then(|b| Some((b, b.terminator()?)))
.unwrap();
let builder = OpBuilder::new(context);
let a = block.argument(1)?;
let b = block.argument(2)?;
let self_value = block.argument(0)?;
let c = block
.insert_operation_before(
ret_op,
dialect::r#struct::readm(
&builder,
location,
FeltType::new(context).into(),
self_value.into(),
out_field.member_name(),
)?,
)
.result(0)?;
let t = block
.insert_operation_before(ret_op, dialect::felt::mul(location, c.into(), b.into())?)
.result(0)?;
block.insert_operation_before(ret_op, dialect::constrain::eq(location, t.into(), a.into()));
Ok(constrain_fn.into())
}