678: Bug 662 Fix r=collinc97 a=gluax

Allows -field values in input values, resolves #662. Also add tests for that and group - input values. Cleans up the re-written code used in a few places by adding a pub crate function. Depends on #626.

Co-authored-by: gluax <jonathan.t.pavlik@gmail.com>
Co-authored-by: gluax <16431709+gluax@users.noreply.github.com>
This commit is contained in:
bors[bot] 2021-02-19 22:10:36 +00:00 committed by GitHub
commit 211fcb0195
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 80 additions and 61 deletions

View File

@ -16,7 +16,7 @@
//! A data type that represents a field value //! A data type that represents a field value
use crate::errors::FieldError; use crate::{errors::FieldError, number_string_typing};
use leo_ast::Span; use leo_ast::Span;
use snarkvm_errors::gadgets::SynthesisError; use snarkvm_errors::gadgets::SynthesisError;
@ -54,22 +54,14 @@ impl<F: PrimeField> FieldType<F> {
} }
pub fn constant(string: String, span: &Span) -> Result<Self, FieldError> { pub fn constant(string: String, span: &Span) -> Result<Self, FieldError> {
let first_char = string.chars().next().unwrap(); let number_info = number_string_typing(&string);
let new_string: &str;
let value;
// Check if first symbol is a negative. let value = match number_info {
// If so strip it, parse rest of string and then negate it. (number, neg) if neg => {
if first_char == '-' { -F::from_str(&number).map_err(|_| FieldError::invalid_field(string, span.to_owned()))?
new_string = string }
.chars() (number, _) => F::from_str(&number).map_err(|_| FieldError::invalid_field(string, span.to_owned()))?,
.next() };
.map(|c| &string[c.len_utf8()..])
.ok_or_else(|| FieldError::invalid_field(string.clone(), span.to_owned()))?;
value = -F::from_str(&new_string).map_err(|_| FieldError::invalid_field(string, span.to_owned()))?;
} else {
value = F::from_str(&string).map_err(|_| FieldError::invalid_field(string, span.to_owned()))?;
}
Ok(FieldType::Constant(value)) Ok(FieldType::Constant(value))
} }

View File

@ -16,7 +16,7 @@
//! Methods to enforce constraints on input field values in a compiled Leo program. //! Methods to enforce constraints on input field values in a compiled Leo program.
use crate::{errors::FieldError, value::ConstrainedValue, FieldType, GroupType}; use crate::{errors::FieldError, number_string_typing, value::ConstrainedValue, FieldType, GroupType};
use leo_ast::{InputValue, Span}; use leo_ast::{InputValue, Span};
use snarkvm_errors::gadgets::SynthesisError; use snarkvm_errors::gadgets::SynthesisError;
@ -31,11 +31,26 @@ pub(crate) fn allocate_field<F: PrimeField, CS: ConstraintSystem<F>>(
option: Option<String>, option: Option<String>,
span: &Span, span: &Span,
) -> Result<FieldType<F>, FieldError> { ) -> Result<FieldType<F>, FieldError> {
FieldType::alloc( match option {
cs.ns(|| format!("`{}: field` {}:{}", name, span.line, span.start)), Some(string) => {
|| option.ok_or(SynthesisError::AssignmentMissing), let number_info = number_string_typing(&string);
)
.map_err(|_| FieldError::missing_field(format!("{}: field", name), span.to_owned())) match number_info {
(number, neg) if neg => FieldType::alloc(
cs.ns(|| format!("`{}: field` {}:{}", name, span.line, span.start)),
|| Some(number).ok_or(SynthesisError::AssignmentMissing),
)
.map(|value| value.negate(cs, span))
.map_err(|_| FieldError::missing_field(format!("{}: field", name), span.to_owned()))?,
(number, _) => FieldType::alloc(
cs.ns(|| format!("`{}: field` {}:{}", name, span.line, span.start)),
|| Some(number).ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| FieldError::missing_field(format!("{}: field", name), span.to_owned())),
}
}
None => Err(FieldError::missing_field(format!("{}: field", name), span.to_owned())),
}
} }
pub(crate) fn field_from_input<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>( pub(crate) fn field_from_input<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{errors::GroupError, GroupType}; use crate::{errors::GroupError, number_string_typing, GroupType};
use leo_asg::{GroupCoordinate, GroupValue, Span}; use leo_asg::{GroupCoordinate, GroupValue, Span};
use snarkvm_curves::{ use snarkvm_curves::{
@ -133,23 +133,6 @@ impl GroupType<Fq> for EdwardsGroupType {
} }
} }
fn number_string_typing(number: &str, span: &Span) -> Result<(String, bool), GroupError> {
let first_char = number.chars().next().unwrap();
// Check if first symbol is a negative.
// If so strip it, parse rest of string and then negate it.
if first_char == '-' {
let uint = number
.chars()
.next()
.map(|c| &number[c.len_utf8()..])
.ok_or_else(|| GroupError::invalid_group(number.to_string(), span.to_owned()))?;
Ok((uint.to_string(), true))
} else {
Ok((number.to_string(), false))
}
}
impl EdwardsGroupType { impl EdwardsGroupType {
pub fn edwards_affine_from_value(value: &GroupValue, span: &Span) -> Result<EdwardsAffine, GroupError> { pub fn edwards_affine_from_value(value: &GroupValue, span: &Span) -> Result<EdwardsAffine, GroupError> {
match value { match value {
@ -159,7 +142,7 @@ impl EdwardsGroupType {
} }
pub fn edwards_affine_from_single(number: &str, span: &Span) -> Result<EdwardsAffine, GroupError> { pub fn edwards_affine_from_single(number: &str, span: &Span) -> Result<EdwardsAffine, GroupError> {
let number_info = number_string_typing(number, &span.clone())?; let number_info = number_string_typing(number);
if number_info.0.eq("0") { if number_info.0.eq("0") {
Ok(EdwardsAffine::zero()) Ok(EdwardsAffine::zero())
@ -189,41 +172,35 @@ impl EdwardsGroupType {
match (x, y) { match (x, y) {
// (x, y) // (x, y)
(GroupCoordinate::Number(x_string), GroupCoordinate::Number(y_string)) => Self::edwards_affine_from_pair( (GroupCoordinate::Number(x_string), GroupCoordinate::Number(y_string)) => Self::edwards_affine_from_pair(
number_string_typing(&x_string, &span.clone())?, number_string_typing(&x_string),
number_string_typing(&y_string, &span.clone())?, number_string_typing(&y_string),
span, span,
span, span,
span, span,
), ),
// (x, +) // (x, +)
(GroupCoordinate::Number(x_string), GroupCoordinate::SignHigh) => { (GroupCoordinate::Number(x_string), GroupCoordinate::SignHigh) => {
Self::edwards_affine_from_x_str(number_string_typing(&x_string, &span.clone())?, span, Some(true), span) Self::edwards_affine_from_x_str(number_string_typing(&x_string), span, Some(true), span)
} }
// (x, -) // (x, -)
(GroupCoordinate::Number(x_string), GroupCoordinate::SignLow) => Self::edwards_affine_from_x_str( (GroupCoordinate::Number(x_string), GroupCoordinate::SignLow) => {
number_string_typing(&x_string, &span.clone())?, Self::edwards_affine_from_x_str(number_string_typing(&x_string), span, Some(false), span)
span, }
Some(false),
span,
),
// (x, _) // (x, _)
(GroupCoordinate::Number(x_string), GroupCoordinate::Inferred) => { (GroupCoordinate::Number(x_string), GroupCoordinate::Inferred) => {
Self::edwards_affine_from_x_str(number_string_typing(&x_string, &span.clone())?, span, None, span) Self::edwards_affine_from_x_str(number_string_typing(&x_string), span, None, span)
} }
// (+, y) // (+, y)
(GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string)) => { (GroupCoordinate::SignHigh, GroupCoordinate::Number(y_string)) => {
Self::edwards_affine_from_y_str(number_string_typing(&y_string, &span.clone())?, span, Some(true), span) Self::edwards_affine_from_y_str(number_string_typing(&y_string), span, Some(true), span)
} }
// (-, y) // (-, y)
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string)) => Self::edwards_affine_from_y_str( (GroupCoordinate::SignLow, GroupCoordinate::Number(y_string)) => {
number_string_typing(&y_string, &span.clone())?, Self::edwards_affine_from_y_str(number_string_typing(&y_string), span, Some(false), span)
span, }
Some(false),
span,
),
// (_, y) // (_, y)
(GroupCoordinate::Inferred, GroupCoordinate::Number(y_string)) => { (GroupCoordinate::Inferred, GroupCoordinate::Number(y_string)) => {
Self::edwards_affine_from_y_str(number_string_typing(&y_string, &span.clone())?, span, None, span) Self::edwards_affine_from_y_str(number_string_typing(&y_string), span, None, span)
} }
// Invalid // Invalid
(x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span.clone())), (x, y) => Err(GroupError::invalid_group(format!("({}, {})", x, y), span.clone())),

View File

@ -32,3 +32,16 @@ pub use self::integer::*;
pub mod value; pub mod value;
pub use self::value::*; pub use self::value::*;
pub(crate) fn number_string_typing(number: &str) -> (String, bool) {
let first_char = number.chars().next().unwrap();
// Check if first symbol is a negative.
// If so strip it, parse rest of string and then negate it.
if first_char == '-' {
let uint = number.chars().next().map(|c| &number[c.len_utf8()..]).unwrap_or("");
(uint.to_string(), true)
} else {
(number.to_string(), false)
}
}

View File

@ -1,2 +1,3 @@
[main] [main]
a: field = 1; a: field = 1;
b: field = -1;

View File

@ -0,0 +1,4 @@
[main]
a: group = 1group;
b: group = -1group;
c: group = (0, -1)group;

View File

@ -1,4 +1,5 @@
function main(a: field) { function main(a: field, b: field) {
// Change to assert when == is implemented for field. // Change to assert when == is implemented for field.
console.log("a: {}", a); console.log("a: {}", a);
console.log("b: {}", b);
} }

View File

@ -0,0 +1,6 @@
function main(a: group, b: group, c: group) {
// Change to assert when == is implemented for group.
console.log("a: {}", a);
console.log("b: {}", b);
console.log("c: {}", c);
}

View File

@ -103,3 +103,13 @@ fn test_field_input() {
assert_satisfied(program); assert_satisfied(program);
} }
#[test]
fn test_group_input() {
let program_string = include_str!("main_group.leo");
let input_string = include_str!("input/main_group.in");
let program = parse_program_with_input(program_string, input_string).unwrap();
assert_satisfied(program);
}