impl circuit static, self, and failure tests

This commit is contained in:
collin 2020-05-20 12:45:40 -07:00
parent 50bf469d8b
commit e07d43c287
19 changed files with 319 additions and 22 deletions

View File

@ -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(),
))

View File

@ -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)

View File

@ -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)))
}

View File

@ -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(),

View File

@ -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),

View File

@ -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(

View File

@ -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)

View File

@ -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)
}
}

View File

@ -0,0 +1,3 @@
function main() {
let c = Circ { };
}

View File

@ -0,0 +1,9 @@
circuit Circ {
x: u32
}
function main() -> u32 {
let c = Circ { x: 1u32 };
return c.x
}

View File

@ -0,0 +1,9 @@
circuit Circ {
x: u32
}
function main() -> u32 {
let c = Circ { x: 1u32 };
return c.y
}

View File

@ -0,0 +1,10 @@
circuit Circ {
function echo(x: u32) -> u32 {
return x
}
}
function main() -> u32 {
let c = Circ { };
return c.echoed(1u32)
}

View 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 `::`
}

View File

@ -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 `.`
}

View File

@ -0,0 +1,9 @@
circuit Circ {
static function echo(x: u32) -> u32 {
return x
}
}
function main() -> u32 {
return Circ::echoed(1u32)
}

View File

@ -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);
// }

View 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
}

View File

@ -0,0 +1,9 @@
circuit Circ {
static function new() -> Self {
return Self { }
}
}
function main() -> Circ {
return Circ::new()
}

View File

@ -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(