Merge pull request #2427 from AleoHQ/feat/group-to-coordinate

[Feature] Support `to_x_coordinate` for `group`s.
This commit is contained in:
d0cd 2023-06-28 11:32:57 -04:00 committed by GitHub
commit c373b898c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 209 additions and 11 deletions

View File

@ -36,6 +36,10 @@ pub enum UnaryOperation {
Square,
/// Square root operation, i.e. `.sqrt()`.
SquareRoot,
/// Converts a group element to its x-coordinate, i.e. `.to_x_coordinate()`.
ToXCoordinate,
/// Converts a group element to its y-coordinate, i.e. `.to_y_coordinate()`.
ToYCoordinate,
}
impl UnaryOperation {
@ -50,6 +54,8 @@ impl UnaryOperation {
sym::not => Self::Not,
sym::square => Self::Square,
sym::square_root => Self::SquareRoot,
sym::to_x_coordinate => Self::ToXCoordinate,
sym::to_y_coordinate => Self::ToYCoordinate,
_ => return None,
})
}
@ -65,6 +71,8 @@ impl UnaryOperation {
Self::Not => "not",
Self::Square => "square",
Self::SquareRoot => "square_root",
Self::ToXCoordinate => "to_x_coordinate",
Self::ToYCoordinate => "to_y_coordinate",
}
}
}

View File

@ -175,6 +175,9 @@ pub enum CoreFunction {
MappingGet,
MappingGetOrUse,
MappingSet,
GroupToXCoordinate,
GroupToYCoordinate,
}
impl CoreFunction {
@ -338,6 +341,9 @@ impl CoreFunction {
(sym::Mapping, sym::get) => Self::MappingGet,
(sym::Mapping, sym::get_or_use) => Self::MappingGetOrUse,
(sym::Mapping, sym::set) => Self::MappingSet,
(sym::group, sym::to_x_coordinate) => Self::GroupToXCoordinate,
(sym::group, sym::to_y_coordinate) => Self::GroupToYCoordinate,
_ => return None,
})
}
@ -502,6 +508,9 @@ impl CoreFunction {
Self::MappingGet => 2,
Self::MappingGetOrUse => 3,
Self::MappingSet => 3,
Self::GroupToXCoordinate => 1,
Self::GroupToYCoordinate => 1,
}
}
}

View File

@ -149,19 +149,22 @@ impl<'a> CodeGenerator<'a> {
fn visit_unary(&mut self, input: &'a UnaryExpression) -> (String, String) {
let (expression_operand, expression_instructions) = self.visit_expression(&input.receiver);
let opcode = match input.op {
UnaryOperation::Abs => String::from("abs"),
UnaryOperation::AbsWrapped => String::from("abs.w"),
UnaryOperation::Double => String::from("double"),
UnaryOperation::Inverse => String::from("inv"),
UnaryOperation::Not => String::from("not"),
UnaryOperation::Negate => String::from("neg"),
UnaryOperation::Square => String::from("square"),
UnaryOperation::SquareRoot => String::from("sqrt"),
// Note that non-empty suffixes must be preceded by a space.
let (opcode, suffix) = match input.op {
UnaryOperation::Abs => ("abs", ""),
UnaryOperation::AbsWrapped => ("abs.w", ""),
UnaryOperation::Double => ("double", ""),
UnaryOperation::Inverse => ("inv", ""),
UnaryOperation::Not => ("not", ""),
UnaryOperation::Negate => ("neg", ""),
UnaryOperation::Square => ("square", ""),
UnaryOperation::SquareRoot => ("sqrt", ""),
UnaryOperation::ToXCoordinate => ("cast", " as group.x"),
UnaryOperation::ToYCoordinate => ("cast", " as group.y"),
};
let destination_register = format!("r{}", self.next_register);
let unary_instruction = format!(" {opcode} {expression_operand} into {destination_register};\n");
let unary_instruction = format!(" {opcode} {expression_operand} into {destination_register}{suffix};\n");
// Increment the register counter.
self.next_register += 1;
@ -299,7 +302,7 @@ impl<'a> CodeGenerator<'a> {
};
// Construct the instruction.
let (destination, instruction) = match input.ty {
let (destination, instruction) = match &input.ty {
Type::Identifier(Identifier { name: sym::BHP256, .. }) => {
construct_simple_function_call(&input.name, "bhp256", arguments)
}
@ -357,6 +360,27 @@ impl<'a> CodeGenerator<'a> {
}
_ => unreachable!("The only variants of Mapping are get, get_or, and set"),
},
Type::Identifier(Identifier { name: sym::group, .. }) => {
match input.name {
Identifier { name: sym::to_x_coordinate, .. } => {
let mut instruction = " cast".to_string();
let destination_register = get_destination_register();
// Write the argument and the destination register.
writeln!(instruction, " {} into {destination_register} as group.x;", arguments[0],)
.expect("failed to write to string");
(destination_register, instruction)
}
Identifier { name: sym::to_y_coordinate, .. } => {
let mut instruction = " cast".to_string();
let destination_register = get_destination_register();
// Write the argument and the destination register.
writeln!(instruction, " {} into {destination_register} as group.y;", arguments[0],)
.expect("failed to write to string");
(destination_register, instruction)
}
_ => unreachable!("The only associated methods of group are to_x_coordinate and to_y_coordinate"),
}
}
_ => unreachable!("All core functions should be known at this phase of compilation"),
};
// Add the instruction to the list of instructions.

View File

@ -730,6 +730,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
self.assert_field_type(destination, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::ToXCoordinate | UnaryOperation::ToYCoordinate => {
// Only field type.
self.assert_field_type(destination, input.span());
self.visit_expression(&input.receiver, &Some(Type::Group))
}
}
}

View File

@ -861,6 +861,11 @@ impl<'a> TypeChecker<'a> {
None
}
}
CoreFunction::GroupToXCoordinate | CoreFunction::GroupToYCoordinate => {
// Check that the first argument is a group.
self.assert_group_type(&arguments[0].0, arguments[0].1);
Some(Type::Field)
}
}
}

View File

@ -15,6 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
#![forbid(unsafe_code)]
#![recursion_limit = "256"]
pub mod symbol;
pub use symbol::{sym, Symbol};

View File

@ -175,6 +175,8 @@ symbols! {
Poseidon4,
Poseidon8,
set,
to_x_coordinate,
to_y_coordinate,
// types
address,

View File

@ -0,0 +1,12 @@
---
namespace: Compile
expectation: Pass
outputs:
- - initial_ast: 20332c6a83a3628dd4f17d8653acdf28dd8e54bcaf9cab071fda7cbbf3ff3d29
unrolled_ast: 20332c6a83a3628dd4f17d8653acdf28dd8e54bcaf9cab071fda7cbbf3ff3d29
ssa_ast: 2bfa5ff05133abdf9553186a96a35c8466b5a49366ea07cea92e01f30c04f769
flattened_ast: f7fd524a8a3e98f0e01f4c71b09bea3032867a086447ea72f4cdded1a581983d
inlined_ast: f7fd524a8a3e98f0e01f4c71b09bea3032867a086447ea72f4cdded1a581983d
dce_ast: 644ec7d38093f28ca0b0908282d7ff8032f7b22a0cf98c47d5ffa0ad16f047b8
bytecode: 51e95e10668242bec30e9917715d9856da632e933c33207ee41c5ed38d6366aa
warnings: ""

View File

@ -0,0 +1,12 @@
---
namespace: Compile
expectation: Pass
outputs:
- - initial_ast: 62e89c72fcd4f62002450d1c82060f2f662ad6e1c12a19f0e6b994c50ba0491b
unrolled_ast: 62e89c72fcd4f62002450d1c82060f2f662ad6e1c12a19f0e6b994c50ba0491b
ssa_ast: b3c38a64899eef777c4bdd38d5db3f68148334795f4e9b89449eb9148db03eb3
flattened_ast: da24a573e4ff569e242f88f73869c2251e19bb5ae62ef602773c0a48863bb9b3
inlined_ast: da24a573e4ff569e242f88f73869c2251e19bb5ae62ef602773c0a48863bb9b3
dce_ast: d313e678afef867d5cbca6829c81515387bcc768eeb4044b25c7996f4d177c63
bytecode: ea2e94f0f589fac4565040575643b1b7cd7813fe513d5b09b17c191bbf0f727e
warnings: ""

View File

@ -0,0 +1,18 @@
---
namespace: Execute
expectation: Pass
outputs:
- - initial_ast: ccfa20fa35d720984742081098965806736ba374ad046b3aadf6d899663375da
unrolled_ast: ccfa20fa35d720984742081098965806736ba374ad046b3aadf6d899663375da
ssa_ast: ab06973a60d8da80b174deae3dc4ee88216894503e613d3ba3ecd74c7f38e408
flattened_ast: 9a9c3bc868b2e83c0cb0822e5bbf1d6f782f7992e0b748c6390a57768c44a4a7
inlined_ast: 9a9c3bc868b2e83c0cb0822e5bbf1d6f782f7992e0b748c6390a57768c44a4a7
dce_ast: 9a9c3bc868b2e83c0cb0822e5bbf1d6f782f7992e0b748c6390a57768c44a4a7
bytecode: 5c20fda21a40464a1462524cf913438776a39383a671949312f48ce8ceb2dd16
warnings: ""
results:
main:
- input: "[0group]"
output: "[0field, 1field]"
- input: "[2group]"
output: "[2field, 5553594316923449299484601589326170487897520766531075014687114064346375156608field]"

View File

@ -0,0 +1,24 @@
---
namespace: ParseExpression
expectation: Pass
outputs:
- Access:
AssociatedFunction:
ty:
Identifier: "{\"name\":\"group\",\"span\":\"{\\\"lo\\\":0,\\\"hi\\\":5}\"}"
name: "{\"name\":\"to_x_coordinate\",\"span\":\"{\\\"lo\\\":7,\\\"hi\\\":22}\"}"
arguments:
- Identifier: "{\"name\":\"a\",\"span\":\"{\\\"lo\\\":23,\\\"hi\\\":24}\"}"
span:
lo: 0
hi: 25
- Access:
AssociatedFunction:
ty:
Identifier: "{\"name\":\"group\",\"span\":\"{\\\"lo\\\":0,\\\"hi\\\":5}\"}"
name: "{\"name\":\"to_y_coordinate\",\"span\":\"{\\\"lo\\\":7,\\\"hi\\\":22}\"}"
arguments:
- Identifier: "{\"name\":\"a\",\"span\":\"{\\\"lo\\\":23,\\\"hi\\\":24}\"}"
span:
lo: 0
hi: 25

View File

@ -0,0 +1,18 @@
---
namespace: ParseExpression
expectation: Pass
outputs:
- Unary:
receiver:
Identifier: "{\"name\":\"a\",\"span\":\"{\\\"lo\\\":0,\\\"hi\\\":1}\"}"
op: ToXCoordinate
span:
lo: 0
hi: 19
- Unary:
receiver:
Identifier: "{\"name\":\"b\",\"span\":\"{\\\"lo\\\":0,\\\"hi\\\":1}\"}"
op: ToYCoordinate
span:
lo: 0
hi: 19

View File

@ -0,0 +1,12 @@
/*
namespace: Compile
expectation: Pass
*/
program test.aleo {
transition main(a: group) -> field {
let x: field = a.to_x_coordinate();
let y: field = 0group.to_y_coordinate();
return group::to_x_coordinate(a);
}
}

View File

@ -0,0 +1,12 @@
/*
namespace: Compile
expectation: Pass
*/
program test.aleo {
transition main(a: group) -> field {
let x: field = a.to_x_coordinate();
let y: field = 0group.to_y_coordinate();
return group::to_y_coordinate(a);
}
}

View File

@ -0,0 +1,22 @@
/*
namespace: Execute
expectation: Pass
cases:
main:
- input: ["0group"]
- input: ["2group"]
*/
program test.aleo {
transition main(a: group) -> (field, field) {
let b: field = group::to_x_coordinate(a);
let c: field = a as field;
let e: field = a.to_x_coordinate();
assert_eq(b, c);
assert_eq(b, e);
let d: field = group::to_y_coordinate(a);
let f: field = a.to_y_coordinate();
assert_eq(d, f);
return (b, d);
}
}

View File

@ -0,0 +1,7 @@
/*
namespace: ParseExpression
expectation: Pass
*/
group::to_x_coordinate(a)
group::to_y_coordinate(a)

View File

@ -0,0 +1,7 @@
/*
namespace: ParseExpression
expectation: Pass
*/
a.to_x_coordinate()
b.to_y_coordinate()