diff --git a/compiler/src/errors/value/group.rs b/compiler/src/errors/value/group.rs index 5934282406..6720397913 100644 --- a/compiler/src/errors/value/group.rs +++ b/compiler/src/errors/value/group.rs @@ -52,4 +52,34 @@ impl GroupError { Self::new_from_span(message, span) } + + pub fn x_invalid(x: String, span: Span) -> Self { + let message = format!("invalid x coordinate `{}`", x); + + Self::new_from_span(message, span) + } + + pub fn y_invalid(y: String, span: Span) -> Self { + let message = format!("invalid y coordinate `{}`", y); + + Self::new_from_span(message, span) + } + + pub fn not_on_curve(element: String, span: Span) -> Self { + let message = format!("group element `{}` is not on the supported curve", element); + + Self::new_from_span(message, span) + } + + pub fn x_recover(span: Span) -> Self { + let message = format!("could not recover group element from x coordinate"); + + Self::new_from_span(message, span) + } + + pub fn y_recover(span: Span) -> Self { + let message = format!("could not recover group element from x coordinate"); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/errors/value/value.rs b/compiler/src/errors/value/value.rs index af47546962..5c824f40ec 100644 --- a/compiler/src/errors/value/value.rs +++ b/compiler/src/errors/value/value.rs @@ -45,4 +45,10 @@ impl ValueError { Self::new_from_span(message, span) } + + pub fn implicit_group(span: Span) -> Self { + let message = format!("group coordinates should be in (x, y)group format"); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 3aaca3e829..e8b2ebaef2 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -38,7 +38,7 @@ impl> ConstrainedProgram { Expression::Address(address, span) => Ok(ConstrainedValue::Address(Address::new(address, span)?)), Expression::Boolean(boolean, span) => Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, span)?)), Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)), - Expression::Group(group_affine, span) => Ok(ConstrainedValue::Group(G::constant(group_affine, span)?)), + Expression::Group(group_affine) => Ok(ConstrainedValue::Group(G::constant(group_affine)?)), Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_type, value, span)?), Expression::Integer(type_, integer, span) => { Ok(ConstrainedValue::Integer(Integer::new_constant(&type_, integer, span)?)) diff --git a/compiler/src/value/group/group_type.rs b/compiler/src/value/group/group_type.rs index 71cbdad435..ed863625c7 100644 --- a/compiler/src/value/group/group_type.rs +++ b/compiler/src/value/group/group_type.rs @@ -1,7 +1,7 @@ //! A data type that represents members in the group formed by the set of affine points on a curve. use crate::errors::GroupError; -use leo_typed::Span; +use leo_typed::{GroupValue, Span}; use snarkos_models::{ curves::{Field, One}, @@ -32,7 +32,7 @@ pub trait GroupType: + ToBitsGadget + ToBytesGadget { - fn constant(string: String, span: Span) -> Result; + fn constant(value: GroupValue) -> Result; fn to_allocated>(&self, cs: CS, span: Span) -> Result; diff --git a/compiler/src/value/group/targets/edwards_bls12.rs b/compiler/src/value/group/targets/edwards_bls12.rs index 0b9fadd7ca..308d56d276 100644 --- a/compiler/src/value/group/targets/edwards_bls12.rs +++ b/compiler/src/value/group/targets/edwards_bls12.rs @@ -1,5 +1,5 @@ use crate::{errors::GroupError, GroupType}; -use leo_typed::Span; +use leo_typed::{GroupCoordinate, GroupValue, Span}; use snarkos_curves::{ edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq}, @@ -36,14 +36,43 @@ pub enum EdwardsGroupType { } impl GroupType for EdwardsGroupType { - fn constant(string: String, span: Span) -> Result { - // 1group = generator - if string.eq("1") { - return Ok(Self::one()); - } + fn constant(group: GroupValue) -> Result { + let span = group.span; + let x = group.x; + let y = group.y; - let value = - Self::edwards_affine_from_str(string.clone()).map_err(|_| GroupError::invalid_group(string, span))?; + 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)), + }; Ok(EdwardsGroupType::Constant(value)) } @@ -124,8 +153,85 @@ impl GroupType for EdwardsGroupType { } impl EdwardsGroupType { + pub fn edwards_affine_from_x_str( + x_string: String, + x_span: Span, + greatest: Option, + element_span: Span, + ) -> Result { + let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span))?; + match greatest { + // Sign provided + Some(greatest) => EdwardsAffine::from_x_coordinate(x, greatest).ok_or(GroupError::x_recover(element_span)), + // Sign inferred + None => { + // 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(GroupError::x_recover(element_span)) + } + } + } + + pub fn edwards_affine_from_y_str( + y_string: String, + y_span: Span, + _greatest: Option, + _element_span: Span, + ) -> Result { + let _y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span))?; + + unimplemented!("recover from_y_coordinate not implemented for Edwards Affine") + // match greatest { + // // Sign provided + // Some(greatest) => EdwardsAffine::from_y_coordinate(y, greatest).ok_or(GroupError::y_recover(element_span)), + // // Sign inferred + // None => { + // // Attempt to recover with a sign_low bit. + // if let Some(element) = EdwardsAffine::from_y_coordinate(y.clone(), false) { + // return Ok(element); + // } + // + // // Attempt to recover with a sign_high bit. + // if let Some(element) = EdwardsAffine::from_y_coordinate(y, true) { + // return Ok(element); + // } + // + // // Otherwise return error. + // Err(GroupError::y_recover(element_span)) + // } + // } + } + + pub fn edwards_affine_from_pair( + x_string: String, + y_string: String, + x_span: Span, + y_span: Span, + element_span: Span, + ) -> Result { + let x = Fq::from_str(&x_string).map_err(|_| GroupError::x_invalid(x_string, x_span))?; + let y = Fq::from_str(&y_string).map_err(|_| GroupError::y_invalid(y_string, y_span))?; + + let element = EdwardsAffine::new(x, y); + + if element.is_on_curve() { + Ok(element) + } else { + Err(GroupError::not_on_curve(format!("{}", element), element_span)) + } + } + pub fn edwards_affine_from_str(string: String) -> Result { - // x or (x, y) + // (x, y) match Fq::from_str(&string).ok() { Some(x) => { // Attempt to recover with a sign_low bit. diff --git a/compiler/src/value/value.rs b/compiler/src/value/value.rs index 1f96127f33..2fc3c0053a 100644 --- a/compiler/src/value/value.rs +++ b/compiler/src/value/value.rs @@ -69,7 +69,7 @@ impl> ConstrainedValue { Type::Address => Ok(ConstrainedValue::Address(Address::new(value, span)?)), Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)), Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)), - Type::Group => Ok(ConstrainedValue::Group(G::constant(value, span)?)), + Type::Group => Err(ValueError::implicit_group(span)), Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::new_constant( integer_type, value, diff --git a/typed/src/groups/group_coordinate.rs b/typed/src/groups/group_coordinate.rs index 76ed0df86f..a2806d0af7 100644 --- a/typed/src/groups/group_coordinate.rs +++ b/typed/src/groups/group_coordinate.rs @@ -13,9 +13,9 @@ use std::fmt; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum GroupCoordinate { Number(String, Span), - SignHigh(Span), - SignLow(Span), - Inferred(Span), + SignHigh, + SignLow, + Inferred, } impl<'ast> From> for GroupCoordinate { @@ -33,9 +33,9 @@ impl fmt::Display for GroupCoordinate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { GroupCoordinate::Number(number, _) => write!(f, "{}", number), - GroupCoordinate::SignHigh(_) => write!(f, "+"), - GroupCoordinate::SignLow(_) => write!(f, "-"), - GroupCoordinate::Inferred(_) => write!(f, "_"), + GroupCoordinate::SignHigh => write!(f, "+"), + GroupCoordinate::SignLow => write!(f, "-"), + GroupCoordinate::Inferred => write!(f, "_"), } } } @@ -50,19 +50,19 @@ impl<'ast> From> for GroupCoordinate { } impl<'ast> From> for GroupCoordinate { - fn from(sign: AstSignHigh<'ast>) -> Self { - GroupCoordinate::SignHigh(Span::from(sign.span)) + fn from(_sign: AstSignHigh<'ast>) -> Self { + GroupCoordinate::SignHigh } } impl<'ast> From> for GroupCoordinate { - fn from(sign: AstSignLow<'ast>) -> Self { - GroupCoordinate::SignLow(Span::from(sign.span)) + fn from(_sign: AstSignLow<'ast>) -> Self { + GroupCoordinate::SignLow } } impl<'ast> From> for GroupCoordinate { - fn from(sign: AstInferred<'ast>) -> Self { - GroupCoordinate::Inferred(Span::from(sign.span)) + fn from(_sign: AstInferred<'ast>) -> Self { + GroupCoordinate::Inferred } }