mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-28 04:35:33 +03:00
impl circuit static, self, and failure tests
This commit is contained in:
parent
50bf469d8b
commit
e07d43c287
@ -377,6 +377,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
Integer::conditionally_select(cs, &resolved_first, &integer_2, &integer_3)?;
|
||||
Ok(ConstrainedValue::Integer(result))
|
||||
}
|
||||
// (ConstrainedValue::GroupElement(group_2), ConstrainedValue::GroupElement(group_3)) => {
|
||||
// let result = Group
|
||||
// }
|
||||
(_, _) => {
|
||||
unimplemented!("conditional select gadget not implemented between given types")
|
||||
}
|
||||
@ -630,11 +633,15 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
}
|
||||
}
|
||||
}
|
||||
ConstrainedValue::Static(value) => {
|
||||
return Err(ExpressionError::InvalidStaticAccess(value.to_string()))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(member.1)
|
||||
}
|
||||
None => Err(ExpressionError::UndefinedCircuitObject(
|
||||
None => Err(ExpressionError::UndefinedMemberAccess(
|
||||
circuit_name.to_string(),
|
||||
circuit_member.to_string(),
|
||||
)),
|
||||
}
|
||||
@ -663,7 +670,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
|
||||
// Find static circuit function
|
||||
let matched_function = circuit.members.into_iter().find(|member| match member {
|
||||
CircuitMember::CircuitFunction(_static, _function) => *_static,
|
||||
CircuitMember::CircuitFunction(_static, function) => {
|
||||
function.function_name == circuit_member
|
||||
}
|
||||
_ => false,
|
||||
});
|
||||
|
||||
@ -673,13 +682,13 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
if _static {
|
||||
function
|
||||
} else {
|
||||
return Err(ExpressionError::InvalidStaticFunction(
|
||||
return Err(ExpressionError::InvalidMemberAccess(
|
||||
function.function_name.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(ExpressionError::UndefinedStaticFunction(
|
||||
return Err(ExpressionError::UndefinedStaticAccess(
|
||||
circuit.identifier.to_string(),
|
||||
circuit_member.to_string(),
|
||||
))
|
||||
|
@ -180,6 +180,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
Type::FieldElement => {
|
||||
Ok(self.field_element_from_input(cs, name, private, input_value)?)
|
||||
}
|
||||
Type::GroupElement => {
|
||||
Ok(self.group_element_from_input(cs, name, private, input_value)?)
|
||||
}
|
||||
Type::Boolean => Ok(self.bool_from_input(cs, name, private, input_value)?),
|
||||
Type::Array(_type, dimensions) => {
|
||||
self.allocate_array(cs, name, private, *_type, dimensions, input_value)
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{ConstrainedProgram, ConstrainedValue};
|
||||
use crate::errors::GroupElementError;
|
||||
use crate::{ConstrainedProgram, ConstrainedValue, InputValue};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, Group, PrimeField},
|
||||
@ -6,6 +7,48 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
|
||||
pub(crate) fn group_element_from_input(
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_name: String,
|
||||
_private: bool,
|
||||
input_value: Option<InputValue<F, G>>,
|
||||
) -> Result<ConstrainedValue<F, G>, GroupElementError> {
|
||||
// Check that the parameter value is the correct type
|
||||
// let group_option = match input_value {
|
||||
// Some(input) => {
|
||||
// if let InputValue::Group(group) = input {
|
||||
// Some(group)
|
||||
// } else {
|
||||
// return Err(GroupElementError::InvalidGroup(input.to_string()));
|
||||
// }
|
||||
// }
|
||||
// None => None,
|
||||
// };
|
||||
//
|
||||
// // Check visibility of parameter
|
||||
// let group_value = if private {
|
||||
// cs.alloc(
|
||||
// || name,
|
||||
// || group_option.ok_or(SynthesisError::AssignmentMissing),
|
||||
// )?
|
||||
// } else {
|
||||
// cs.alloc_input(
|
||||
// || name,
|
||||
// || group_option.ok_or(SynthesisError::AssignmentMissing),
|
||||
// )?
|
||||
// };
|
||||
//
|
||||
// Ok(ConstrainedValue::GroupElement())
|
||||
|
||||
// TODO: use group gadget to allocate groups
|
||||
if let Some(InputValue::Group(group)) = input_value {
|
||||
return Ok(ConstrainedValue::GroupElement(group));
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::GroupElement(G::default()))
|
||||
}
|
||||
|
||||
pub fn evaluate_group_eq(group_element_1: G, group_element_2: G) -> ConstrainedValue<F, G> {
|
||||
ConstrainedValue::Boolean(Boolean::constant(group_element_1.eq(&group_element_2)))
|
||||
}
|
||||
|
@ -270,6 +270,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
|
||||
let mut returns = vec![];
|
||||
for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) {
|
||||
let expected_types = vec![ty.clone()];
|
||||
println!("expression {}", expression);
|
||||
println!("expected types {:?}", expected_types);
|
||||
let result = self.enforce_branch(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
|
@ -145,7 +145,7 @@ impl<F: Field + PrimeField, G: Group> fmt::Display for ConstrainedValue<F, G> {
|
||||
unimplemented!("cannot return circuit definition in program")
|
||||
}
|
||||
ConstrainedValue::Function(ref _circuit_option, ref function) => {
|
||||
write!(f, "{}();", function.function_name)
|
||||
write!(f, "{}", function)
|
||||
}
|
||||
ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value),
|
||||
ConstrainedValue::Static(ref value) => write!(f, "static {}", value),
|
||||
|
@ -60,23 +60,23 @@ pub enum ExpressionError {
|
||||
)]
|
||||
UndefinedCircuit(String),
|
||||
|
||||
#[error("Circuit object {} does not exist", _0)]
|
||||
UndefinedCircuitObject(String),
|
||||
|
||||
#[error("Cannot access circuit {}", _0)]
|
||||
InvalidCircuitAccess(String),
|
||||
|
||||
#[error("Expected circuit value {}", _0)]
|
||||
#[error("Expected circuit member {}", _0)]
|
||||
ExpectedCircuitMember(String),
|
||||
|
||||
#[error("Circuit {} has no static function {}", _0, _1)]
|
||||
UndefinedStaticFunction(String, String),
|
||||
#[error("Circuit {} has no member {}", _0, _1)]
|
||||
UndefinedMemberAccess(String, String),
|
||||
|
||||
#[error(
|
||||
"Static access only supported for static circuit functions, got function {}",
|
||||
_0
|
||||
)]
|
||||
InvalidStaticFunction(String),
|
||||
#[error("Non-static member {} must be accessed using `.` syntax", _0)]
|
||||
InvalidMemberAccess(String),
|
||||
|
||||
#[error("Circuit {} has no static member {}", _0, _1)]
|
||||
UndefinedStaticAccess(String, String),
|
||||
|
||||
#[error("Static member {} must be accessed using `::` syntax", _0)]
|
||||
InvalidStaticAccess(String),
|
||||
|
||||
// Functions
|
||||
#[error(
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::errors::{
|
||||
BooleanError, ExpressionError, FieldElementError, IntegerError, StatementError, ValueError,
|
||||
BooleanError, ExpressionError, FieldElementError, GroupElementError, IntegerError,
|
||||
StatementError, ValueError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@ -28,6 +29,9 @@ pub enum FunctionError {
|
||||
#[error("{}", _0)]
|
||||
FieldElementError(FieldElementError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
GroupElementError(GroupElementError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
BooleanError(BooleanError),
|
||||
|
||||
@ -56,6 +60,12 @@ impl From<FieldElementError> for FunctionError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GroupElementError> for FunctionError {
|
||||
fn from(error: GroupElementError) -> Self {
|
||||
FunctionError::GroupElementError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BooleanError> for FunctionError {
|
||||
fn from(error: BooleanError) -> Self {
|
||||
FunctionError::BooleanError(error)
|
||||
|
@ -1,2 +1,16 @@
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GroupElementError {}
|
||||
pub enum GroupElementError {
|
||||
#[error("Expected group element parameter, got {}", _0)]
|
||||
InvalidGroup(String),
|
||||
|
||||
#[error("{}", _0)]
|
||||
SynthesisError(SynthesisError),
|
||||
}
|
||||
|
||||
impl From<SynthesisError> for GroupElementError {
|
||||
fn from(error: SynthesisError) -> Self {
|
||||
GroupElementError::SynthesisError(error)
|
||||
}
|
||||
}
|
||||
|
3
compiler/tests/circuit/inline_undefined.leo
Normal file
3
compiler/tests/circuit/inline_undefined.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let c = Circ { };
|
||||
}
|
9
compiler/tests/circuit/member_field.leo
Normal file
9
compiler/tests/circuit/member_field.leo
Normal file
@ -0,0 +1,9 @@
|
||||
circuit Circ {
|
||||
x: u32
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
let c = Circ { x: 1u32 };
|
||||
|
||||
return c.x
|
||||
}
|
9
compiler/tests/circuit/member_field_fail.leo
Normal file
9
compiler/tests/circuit/member_field_fail.leo
Normal file
@ -0,0 +1,9 @@
|
||||
circuit Circ {
|
||||
x: u32
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
let c = Circ { x: 1u32 };
|
||||
|
||||
return c.y
|
||||
}
|
10
compiler/tests/circuit/member_function_fail.leo
Normal file
10
compiler/tests/circuit/member_function_fail.leo
Normal file
@ -0,0 +1,10 @@
|
||||
circuit Circ {
|
||||
function echo(x: u32) -> u32 {
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
let c = Circ { };
|
||||
return c.echoed(1u32)
|
||||
}
|
10
compiler/tests/circuit/member_function_invalid.leo
Normal file
10
compiler/tests/circuit/member_function_invalid.leo
Normal file
@ -0,0 +1,10 @@
|
||||
circuit Circ {
|
||||
static function echo(x: u32) -> u32 {
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
let c = Circ { };
|
||||
return c.echo(1u32) // echo is a static function and must be accessed using `::`
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
circuit Circ {
|
||||
function echo(x: u32) -> u32 {
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
return Circ::echo(1u32) // echo is a non-static function and must be accessed using `.`
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
circuit Circ {
|
||||
static function echo(x: u32) -> u32 {
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
return Circ::echoed(1u32)
|
||||
}
|
@ -1,9 +1,16 @@
|
||||
use crate::{compile_program, get_error, get_output, integer::u32::output_one};
|
||||
use crate::{
|
||||
compile_program,
|
||||
get_error,
|
||||
get_output,
|
||||
integer::u32::output_one,
|
||||
// group_element::output_zero
|
||||
};
|
||||
|
||||
use leo_compiler::{
|
||||
compiler::Compiler,
|
||||
errors::{CompilerError, ExpressionError, FunctionError, StatementError},
|
||||
ConstrainedCircuitMember, ConstrainedValue, Identifier, Integer,
|
||||
ConstrainedCircuitMember, ConstrainedValue, Expression, Function, Identifier, Integer,
|
||||
Statement, Type,
|
||||
};
|
||||
use snarkos_curves::{bls12_377::Fr, edwards_bls12::EdwardsProjective};
|
||||
use snarkos_models::gadgets::utilities::uint32::UInt32;
|
||||
@ -36,6 +43,15 @@ fn fail_expected_member(program: Compiler<Fr, EdwardsProjective>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn fail_undefined_member(program: Compiler<Fr, EdwardsProjective>) {
|
||||
match get_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(
|
||||
StatementError::ExpressionError(ExpressionError::UndefinedMemberAccess(_, _)),
|
||||
)) => {}
|
||||
error => panic!("Expected undefined circuit member error, got {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
// Expressions
|
||||
|
||||
#[test]
|
||||
@ -50,16 +66,121 @@ fn test_inline_fail() {
|
||||
fail_expected_member(program)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inline_undefined() {
|
||||
let program = compile_program(DIRECTORY_NAME, "inline_undefined.leo").unwrap();
|
||||
match get_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(
|
||||
StatementError::ExpressionError(ExpressionError::UndefinedCircuit(_)),
|
||||
)) => {}
|
||||
error => panic!("Expected undefined circuit error, got {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
// Members
|
||||
|
||||
#[test]
|
||||
fn test_member_field() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_field.leo").unwrap();
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_field_fail() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_field_fail.leo").unwrap();
|
||||
fail_undefined_member(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_function() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_function.leo").unwrap();
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_function_fail() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_function_fail.leo").unwrap();
|
||||
fail_undefined_member(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_function_invalid() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_function_invalid.leo").unwrap();
|
||||
match get_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(
|
||||
StatementError::ExpressionError(ExpressionError::InvalidStaticAccess(_)),
|
||||
)) => {}
|
||||
error => panic!("Expected invalid function error, got {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_static_function() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_static_function.leo").unwrap();
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_static_function_undefined() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_static_function_undefined.leo").unwrap();
|
||||
match get_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(
|
||||
StatementError::ExpressionError(ExpressionError::UndefinedStaticAccess(_, _)),
|
||||
)) => {}
|
||||
error => panic!("Expected undefined static function error, got {}", error),
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_member_static_function_invalid() {
|
||||
let program = compile_program(DIRECTORY_NAME, "member_static_function_invalid.leo").unwrap();
|
||||
match get_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(
|
||||
StatementError::ExpressionError(ExpressionError::InvalidMemberAccess(_)),
|
||||
)) => {}
|
||||
error => panic!("Expected invalid static function error, got {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
// Self
|
||||
#[test]
|
||||
fn test_self() {
|
||||
let program = compile_program(DIRECTORY_NAME, "self.leo").unwrap();
|
||||
let output = get_output(program);
|
||||
|
||||
// circuit Circ {
|
||||
// static function new() -> Self {
|
||||
// return Self { }
|
||||
// }
|
||||
// }
|
||||
assert_eq!(
|
||||
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![
|
||||
ConstrainedValue::CircuitExpression(
|
||||
Identifier::new("Circ".into()),
|
||||
vec![ConstrainedCircuitMember(
|
||||
Identifier::new("new".into()),
|
||||
ConstrainedValue::Static(Box::new(ConstrainedValue::Function(
|
||||
Some(Identifier::new("Circ".into())),
|
||||
Function {
|
||||
function_name: Identifier::new("new".into()),
|
||||
inputs: vec![],
|
||||
returns: vec![Type::SelfType],
|
||||
statements: vec![Statement::Return(vec![Expression::Circuit(
|
||||
Identifier::new("Self".into()),
|
||||
vec![]
|
||||
)])]
|
||||
}
|
||||
)))
|
||||
)]
|
||||
)
|
||||
]),
|
||||
output
|
||||
);
|
||||
}
|
||||
|
||||
// All
|
||||
|
||||
// #[test]
|
||||
// fn test_pedersen_mock() {
|
||||
// let program = compile_program(DIRECTORY_NAME, "pedersen_mock.leo").unwrap();
|
||||
// output_zero(program);
|
||||
// }
|
||||
|
27
compiler/tests/circuit/pedersen_mock.leo
Normal file
27
compiler/tests/circuit/pedersen_mock.leo
Normal file
@ -0,0 +1,27 @@
|
||||
circuit PedersenHash {
|
||||
parameters: group[512]
|
||||
|
||||
static function new(parameters: group[512]) -> Self {
|
||||
return Self { parameters: parameters }
|
||||
}
|
||||
|
||||
function hash(bits: bool[512]) -> group {
|
||||
let mut digest: group = 0;
|
||||
|
||||
for i in 0..512 {
|
||||
let base = if bits[i] ? parameters[i] : 0;
|
||||
digest += base;
|
||||
}
|
||||
|
||||
return digest
|
||||
}
|
||||
}
|
||||
|
||||
function main(parameters: private group[512]) -> group {
|
||||
let pedersen = PedersenHash::new(parameters);
|
||||
|
||||
let input: bool[512] = [true; 512]; // use mock private key until `.bits()` function is implemented
|
||||
let output = pedersen.hash(input);
|
||||
|
||||
return output
|
||||
}
|
9
compiler/tests/circuit/self.leo
Normal file
9
compiler/tests/circuit/self.leo
Normal file
@ -0,0 +1,9 @@
|
||||
circuit Circ {
|
||||
static function new() -> Self {
|
||||
return Self { }
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> Circ {
|
||||
return Circ::new()
|
||||
}
|
@ -6,7 +6,7 @@ use snarkos_models::curves::Group;
|
||||
|
||||
const DIRECTORY_NAME: &str = "tests/group_element/";
|
||||
|
||||
fn output_zero(program: Compiler<Fr, EdwardsProjective>) {
|
||||
pub(crate) fn output_zero(program: Compiler<Fr, EdwardsProjective>) {
|
||||
let output = get_output(program);
|
||||
assert_eq!(
|
||||
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![ConstrainedValue::GroupElement(
|
||||
|
Loading…
Reference in New Issue
Block a user