mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-30 23:33:27 +03:00
impl new group notation for inputs compiler
This commit is contained in:
parent
172431c222
commit
a4b29d2651
@ -27,7 +27,7 @@ pub trait GroupType<F: Field>:
|
||||
+ EvaluateEqGadget<F>
|
||||
+ EqGadget<F>
|
||||
+ ConditionalEqGadget<F>
|
||||
+ AllocGadget<String, F>
|
||||
+ AllocGadget<GroupValue, F>
|
||||
+ CondSelectGadget<F>
|
||||
+ ToBitsGadget<F>
|
||||
+ ToBytesGadget<F>
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Methods to enforce constraints on input group values in a Leo program.
|
||||
|
||||
use crate::{errors::GroupError, ConstrainedValue, GroupType};
|
||||
use leo_typed::{InputValue, Span};
|
||||
use leo_typed::{GroupValue, InputValue, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
@ -12,7 +12,7 @@ use snarkos_models::{
|
||||
pub(crate) fn allocate_group<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
name: String,
|
||||
option: Option<String>,
|
||||
option: Option<GroupValue>,
|
||||
span: Span,
|
||||
) -> Result<G, GroupError> {
|
||||
let group_name = format!("{}: group", name);
|
||||
|
@ -37,42 +37,7 @@ pub enum EdwardsGroupType {
|
||||
|
||||
impl GroupType<Fq> for EdwardsGroupType {
|
||||
fn constant(group: GroupValue) -> Result<Self, GroupError> {
|
||||
let span = group.span;
|
||||
let x = group.x;
|
||||
let y = group.y;
|
||||
|
||||
let value = match (x, y) {
|
||||
// (x, y)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_pair(x_string, y_string, x_span, y_span, span)?
|
||||
}
|
||||
// (x, +)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignHigh) => {
|
||||
Self::edwards_affine_from_x_str(x_string, x_span, Some(true), span)?
|
||||
}
|
||||
// (x, -)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignLow) => {
|
||||
Self::edwards_affine_from_x_str(x_string, x_span, Some(false), span)?
|
||||
}
|
||||
// (x, _)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Inferred) => {
|
||||
Self::edwards_affine_from_x_str(x_string, x_span, None, span)?
|
||||
}
|
||||
// (+, y)
|
||||
(GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_y_str(y_string, y_span, Some(true), span)?
|
||||
}
|
||||
// (-, y)
|
||||
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_y_str(y_string, y_span, Some(false), span)?
|
||||
}
|
||||
// (_, y)
|
||||
(GroupCoordinate::Inferred, GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_y_str(y_string, y_span, None, span)?
|
||||
}
|
||||
// Invalid
|
||||
(x, y) => return Err(GroupError::invalid_group(format!("({}, {})", x, y), span)),
|
||||
};
|
||||
let value = Self::edwards_affine_from_value(group)?;
|
||||
|
||||
Ok(EdwardsGroupType::Constant(value))
|
||||
}
|
||||
@ -153,6 +118,45 @@ impl GroupType<Fq> for EdwardsGroupType {
|
||||
}
|
||||
|
||||
impl EdwardsGroupType {
|
||||
pub fn edwards_affine_from_value(group: GroupValue) -> Result<EdwardsAffine, GroupError> {
|
||||
let span = group.span;
|
||||
let x = group.x;
|
||||
let y = group.y;
|
||||
|
||||
match (x, y) {
|
||||
// (x, y)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_pair(x_string, y_string, x_span, y_span, span)
|
||||
}
|
||||
// (x, +)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignHigh) => {
|
||||
Self::edwards_affine_from_x_str(x_string, x_span, Some(true), span)
|
||||
}
|
||||
// (x, -)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::SignLow) => {
|
||||
Self::edwards_affine_from_x_str(x_string, x_span, Some(false), span)
|
||||
}
|
||||
// (x, _)
|
||||
(GroupCoordinate::Number(x_string, x_span), GroupCoordinate::Inferred) => {
|
||||
Self::edwards_affine_from_x_str(x_string, x_span, None, span)
|
||||
}
|
||||
// (+, y)
|
||||
(GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_y_str(y_string, y_span, Some(true), span)
|
||||
}
|
||||
// (-, y)
|
||||
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_y_str(y_string, y_span, Some(false), span)
|
||||
}
|
||||
// (_, y)
|
||||
(GroupCoordinate::Inferred, GroupCoordinate::Number(y_string, y_span)) => {
|
||||
Self::edwards_affine_from_y_str(y_string, y_span, None, span)
|
||||
}
|
||||
// Invalid
|
||||
(x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn edwards_affine_from_x_str(
|
||||
x_string: String,
|
||||
x_span: Span,
|
||||
@ -230,44 +234,18 @@ impl EdwardsGroupType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn edwards_affine_from_str(string: String) -> Result<EdwardsAffine, SynthesisError> {
|
||||
// (x, y)
|
||||
match Fq::from_str(&string).ok() {
|
||||
Some(x) => {
|
||||
// Attempt to recover with a sign_low bit.
|
||||
if let Some(element) = EdwardsAffine::from_x_coordinate(x.clone(), false) {
|
||||
return Ok(element);
|
||||
}
|
||||
|
||||
// Attempt to recover with a sign_high bit.
|
||||
if let Some(element) = EdwardsAffine::from_x_coordinate(x, true) {
|
||||
return Ok(element);
|
||||
}
|
||||
|
||||
// Otherwise return error.
|
||||
Err(SynthesisError::AssignmentMissing)
|
||||
}
|
||||
None => EdwardsAffine::from_str(&string).map_err(|_| SynthesisError::AssignmentMissing),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_x_helper<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<String>>(
|
||||
pub fn alloc_helper<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<GroupValue>>(
|
||||
value_gen: Fn,
|
||||
) -> Result<EdwardsAffine, SynthesisError> {
|
||||
let affine_string = match value_gen() {
|
||||
let group_value = match value_gen() {
|
||||
Ok(value) => {
|
||||
let string_value = value.borrow().clone();
|
||||
Ok(string_value)
|
||||
let group_value = value.borrow().clone();
|
||||
Ok(group_value)
|
||||
}
|
||||
_ => Err(SynthesisError::AssignmentMissing),
|
||||
}?;
|
||||
|
||||
// 1group = generator
|
||||
if affine_string.eq("1") {
|
||||
Ok(edwards_affine_one())
|
||||
} else {
|
||||
Self::edwards_affine_from_str(affine_string)
|
||||
}
|
||||
Self::edwards_affine_from_value(group_value).map_err(|_| SynthesisError::AssignmentMissing)
|
||||
}
|
||||
|
||||
pub fn allocated<CS: ConstraintSystem<Fq>>(&self, mut cs: CS) -> Result<EdwardsBlsGadget, SynthesisError> {
|
||||
@ -295,24 +273,24 @@ impl EdwardsGroupType {
|
||||
}
|
||||
}
|
||||
|
||||
impl AllocGadget<String, Fq> for EdwardsGroupType {
|
||||
fn alloc<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<String>, CS: ConstraintSystem<Fq>>(
|
||||
impl AllocGadget<GroupValue, Fq> for EdwardsGroupType {
|
||||
fn alloc<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<GroupValue>, CS: ConstraintSystem<Fq>>(
|
||||
cs: CS,
|
||||
value_gen: Fn,
|
||||
) -> Result<Self, SynthesisError> {
|
||||
let value = <EdwardsBlsGadget as AllocGadget<GroupAffine<EdwardsParameters>, Fq>>::alloc(cs, || {
|
||||
Self::alloc_x_helper(value_gen)
|
||||
Self::alloc_helper(value_gen)
|
||||
})?;
|
||||
|
||||
Ok(EdwardsGroupType::Allocated(value))
|
||||
}
|
||||
|
||||
fn alloc_input<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<String>, CS: ConstraintSystem<Fq>>(
|
||||
fn alloc_input<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<GroupValue>, CS: ConstraintSystem<Fq>>(
|
||||
cs: CS,
|
||||
value_gen: Fn,
|
||||
) -> Result<Self, SynthesisError> {
|
||||
let value = <EdwardsBlsGadget as AllocGadget<GroupAffine<EdwardsParameters>, Fq>>::alloc_input(cs, || {
|
||||
Self::alloc_x_helper(value_gen)
|
||||
Self::alloc_helper(value_gen)
|
||||
})?;
|
||||
|
||||
Ok(EdwardsGroupType::Allocated(value))
|
||||
|
3
compiler/tests/group/input/invalid.in
Normal file
3
compiler/tests/group/input/invalid.in
Normal file
@ -0,0 +1,3 @@
|
||||
[main]
|
||||
a: group = (1, 0)group;
|
||||
b: group = (+, +)group;
|
@ -1,3 +0,0 @@
|
||||
[main]
|
||||
a: group = 1;
|
||||
b: group = 1;
|
@ -1,3 +0,0 @@
|
||||
[main]
|
||||
a: group = 1;
|
||||
b: group = 0;
|
3
compiler/tests/group/input/valid.in
Normal file
3
compiler/tests/group/input/valid.in
Normal file
@ -0,0 +1,3 @@
|
||||
[main]
|
||||
a: group = (0, -)group;
|
||||
b: group = (0, _)group;
|
@ -7,18 +7,31 @@ use crate::{
|
||||
parse_program,
|
||||
parse_program_with_input,
|
||||
};
|
||||
use leo_typed::InputValue;
|
||||
use leo_typed::{GroupCoordinate, GroupValue, InputValue, Span};
|
||||
|
||||
use snarkos_curves::edwards_bls12::EdwardsAffine;
|
||||
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
|
||||
pub fn group_to_decimal_string(g: EdwardsAffine) -> String {
|
||||
pub fn group_element_to_input_value(g: EdwardsAffine) -> GroupValue {
|
||||
let x = field_to_decimal_string(g.x);
|
||||
let y = field_to_decimal_string(g.y);
|
||||
|
||||
format!("({}, {})", x, y)
|
||||
format!("({}, {})", x, y);
|
||||
|
||||
let fake_span = Span {
|
||||
text: "".to_string(),
|
||||
line: 0,
|
||||
start: 0,
|
||||
end: 0,
|
||||
};
|
||||
|
||||
GroupValue {
|
||||
x: GroupCoordinate::Number(x, fake_span.clone()),
|
||||
y: GroupCoordinate::Number(y, fake_span.clone()),
|
||||
span: fake_span,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -117,8 +130,8 @@ fn test_point_input() {
|
||||
#[test]
|
||||
fn test_input() {
|
||||
let program_bytes = include_bytes!("input.leo");
|
||||
let input_bytes_pass = include_bytes!("input/one_one.in");
|
||||
let input_bytes_fail = include_bytes!("input/one_zero.in");
|
||||
let input_bytes_pass = include_bytes!("input/valid.in");
|
||||
let input_bytes_fail = include_bytes!("input/invalid.in");
|
||||
|
||||
let program = parse_program_with_input(program_bytes, input_bytes_pass).unwrap();
|
||||
|
||||
@ -126,7 +139,7 @@ fn test_input() {
|
||||
|
||||
let program = parse_program_with_input(program_bytes, input_bytes_fail).unwrap();
|
||||
|
||||
expect_synthesis_error(program);
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -139,15 +152,15 @@ fn test_negate() {
|
||||
let a: EdwardsAffine = rng.gen();
|
||||
let b = a.neg();
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let b_string = group_to_decimal_string(b);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
let b_element = group_element_to_input_value(b);
|
||||
|
||||
let bytes = include_bytes!("negate.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string))),
|
||||
("b", Some(InputValue::Group(b_string))),
|
||||
("a", Some(InputValue::Group(a_element))),
|
||||
("b", Some(InputValue::Group(b_element))),
|
||||
]);
|
||||
program.set_main_input(main_input);
|
||||
|
||||
@ -166,17 +179,17 @@ fn test_add() {
|
||||
let b: EdwardsAffine = rng.gen();
|
||||
let c = a.add(&b);
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let b_string = group_to_decimal_string(b);
|
||||
let c_string = group_to_decimal_string(c);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
let b_element = group_element_to_input_value(b);
|
||||
let c_element = group_element_to_input_value(c);
|
||||
|
||||
let bytes = include_bytes!("add.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string))),
|
||||
("b", Some(InputValue::Group(b_string))),
|
||||
("c", Some(InputValue::Group(c_string))),
|
||||
("a", Some(InputValue::Group(a_element))),
|
||||
("b", Some(InputValue::Group(b_element))),
|
||||
("c", Some(InputValue::Group(c_element))),
|
||||
]);
|
||||
program.set_main_input(main_input);
|
||||
|
||||
@ -195,17 +208,17 @@ fn test_sub() {
|
||||
let b: EdwardsAffine = rng.gen();
|
||||
let c = a.sub(&b);
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let b_string = group_to_decimal_string(b);
|
||||
let c_string = group_to_decimal_string(c);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
let b_element = group_element_to_input_value(b);
|
||||
let c_element = group_element_to_input_value(c);
|
||||
|
||||
let bytes = include_bytes!("sub.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string))),
|
||||
("b", Some(InputValue::Group(b_string))),
|
||||
("c", Some(InputValue::Group(c_string))),
|
||||
("a", Some(InputValue::Group(a_element))),
|
||||
("b", Some(InputValue::Group(b_element))),
|
||||
("c", Some(InputValue::Group(c_element))),
|
||||
]);
|
||||
program.set_main_input(main_input);
|
||||
|
||||
@ -220,14 +233,14 @@ fn test_assert_eq_pass() {
|
||||
for _ in 0..10 {
|
||||
let a: EdwardsAffine = rng.gen();
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
|
||||
let bytes = include_bytes!("assert_eq.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string.clone()))),
|
||||
("b", Some(InputValue::Group(a_string))),
|
||||
("a", Some(InputValue::Group(a_element.clone()))),
|
||||
("b", Some(InputValue::Group(a_element))),
|
||||
]);
|
||||
|
||||
program.set_main_input(main_input);
|
||||
@ -248,15 +261,15 @@ fn test_assert_eq_fail() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let b_string = group_to_decimal_string(b);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
let b_element = group_element_to_input_value(b);
|
||||
|
||||
let bytes = include_bytes!("assert_eq.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string))),
|
||||
("b", Some(InputValue::Group(b_string))),
|
||||
("a", Some(InputValue::Group(a_element))),
|
||||
("b", Some(InputValue::Group(b_element))),
|
||||
]);
|
||||
|
||||
program.set_main_input(main_input);
|
||||
@ -274,8 +287,8 @@ fn test_eq() {
|
||||
let a: EdwardsAffine = rng.gen();
|
||||
let b: EdwardsAffine = rng.gen();
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let b_string = group_to_decimal_string(b);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
let b_element = group_element_to_input_value(b);
|
||||
|
||||
// test equal
|
||||
|
||||
@ -283,8 +296,8 @@ fn test_eq() {
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string.clone()))),
|
||||
("b", Some(InputValue::Group(a_string.clone()))),
|
||||
("a", Some(InputValue::Group(a_element.clone()))),
|
||||
("b", Some(InputValue::Group(a_element.clone()))),
|
||||
("c", Some(InputValue::Boolean(true))),
|
||||
]);
|
||||
|
||||
@ -299,8 +312,8 @@ fn test_eq() {
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
let main_input = generate_main_input(vec![
|
||||
("a", Some(InputValue::Group(a_string))),
|
||||
("b", Some(InputValue::Group(b_string))),
|
||||
("a", Some(InputValue::Group(a_element))),
|
||||
("b", Some(InputValue::Group(b_element))),
|
||||
("c", Some(InputValue::Boolean(c))),
|
||||
]);
|
||||
|
||||
@ -317,8 +330,8 @@ fn test_ternary() {
|
||||
let a: EdwardsAffine = rng.gen();
|
||||
let b: EdwardsAffine = rng.gen();
|
||||
|
||||
let a_string = group_to_decimal_string(a);
|
||||
let b_string = group_to_decimal_string(b);
|
||||
let a_element = group_element_to_input_value(a);
|
||||
let b_element = group_element_to_input_value(b);
|
||||
|
||||
let bytes = include_bytes!("ternary.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
@ -326,9 +339,9 @@ fn test_ternary() {
|
||||
// true -> field a
|
||||
let main_input = generate_main_input(vec![
|
||||
("s", Some(InputValue::Boolean(true))),
|
||||
("a", Some(InputValue::Group(a_string.clone()))),
|
||||
("b", Some(InputValue::Group(b_string.clone()))),
|
||||
("c", Some(InputValue::Group(a_string.clone()))),
|
||||
("a", Some(InputValue::Group(a_element.clone()))),
|
||||
("b", Some(InputValue::Group(b_element.clone()))),
|
||||
("c", Some(InputValue::Group(a_element.clone()))),
|
||||
]);
|
||||
|
||||
program.set_main_input(main_input);
|
||||
@ -340,9 +353,9 @@ fn test_ternary() {
|
||||
// false -> field b
|
||||
let main_input = generate_main_input(vec![
|
||||
("s", Some(InputValue::Boolean(false))),
|
||||
("a", Some(InputValue::Group(a_string))),
|
||||
("b", Some(InputValue::Group(b_string.clone()))),
|
||||
("c", Some(InputValue::Group(b_string))),
|
||||
("a", Some(InputValue::Group(a_element))),
|
||||
("b", Some(InputValue::Group(b_element.clone()))),
|
||||
("c", Some(InputValue::Group(b_element))),
|
||||
]);
|
||||
|
||||
program.set_main_input(main_input);
|
||||
|
3
compiler/tests/group/x_and_y.leo
Normal file
3
compiler/tests/group/x_and_y.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(element: group) {
|
||||
let b = element;
|
||||
}
|
Loading…
Reference in New Issue
Block a user