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

View File

@ -16,7 +16,7 @@
//! 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 snarkvm_errors::gadgets::SynthesisError;
@ -31,11 +31,26 @@ pub(crate) fn allocate_field<F: PrimeField, CS: ConstraintSystem<F>>(
option: Option<String>,
span: &Span,
) -> Result<FieldType<F>, FieldError> {
FieldType::alloc(
cs.ns(|| format!("`{}: field` {}:{}", name, span.line, span.start)),
|| option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| FieldError::missing_field(format!("{}: field", name), span.to_owned()))
match option {
Some(string) => {
let number_info = number_string_typing(&string);
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>>(

View File

@ -14,7 +14,7 @@
// 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/>.
use crate::{errors::GroupError, GroupType};
use crate::{errors::GroupError, number_string_typing, GroupType};
use leo_asg::{GroupCoordinate, GroupValue, Span};
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 {
pub fn edwards_affine_from_value(value: &GroupValue, span: &Span) -> Result<EdwardsAffine, GroupError> {
match value {
@ -159,7 +142,7 @@ impl EdwardsGroupType {
}
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") {
Ok(EdwardsAffine::zero())
@ -189,41 +172,35 @@ impl EdwardsGroupType {
match (x, y) {
// (x, y)
(GroupCoordinate::Number(x_string), GroupCoordinate::Number(y_string)) => Self::edwards_affine_from_pair(
number_string_typing(&x_string, &span.clone())?,
number_string_typing(&y_string, &span.clone())?,
number_string_typing(&x_string),
number_string_typing(&y_string),
span,
span,
span,
),
// (x, +)
(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, -)
(GroupCoordinate::Number(x_string), GroupCoordinate::SignLow) => Self::edwards_affine_from_x_str(
number_string_typing(&x_string, &span.clone())?,
span,
Some(false),
span,
),
(GroupCoordinate::Number(x_string), GroupCoordinate::SignLow) => {
Self::edwards_affine_from_x_str(number_string_typing(&x_string), span, Some(false), span)
}
// (x, _)
(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)
(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)
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string)) => Self::edwards_affine_from_y_str(
number_string_typing(&y_string, &span.clone())?,
span,
Some(false),
span,
),
(GroupCoordinate::SignLow, GroupCoordinate::Number(y_string)) => {
Self::edwards_affine_from_y_str(number_string_typing(&y_string), span, Some(false), span)
}
// (_, y)
(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
(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 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]
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.
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);
}
#[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);
}