mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-24 10:52:29 +03:00
fix circuit type checking
This commit is contained in:
parent
5a0186b93d
commit
52395bba45
@ -52,7 +52,7 @@ pub struct CircuitInitExpression {
|
||||
|
||||
impl fmt::Display for CircuitInitExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {{", self.name)?;
|
||||
write!(f, "{} {{ ", self.name)?;
|
||||
for member in self.members.iter() {
|
||||
write!(f, "{}", member)?;
|
||||
write!(f, ", ")?;
|
||||
|
@ -28,21 +28,21 @@ use leo_span::{sym, Symbol};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
/// Returns `true` if the given symbol matches the name of a core circuit.
|
||||
pub fn is_core_circuit(circuit: Symbol) -> bool {
|
||||
match circuit {
|
||||
sym::bhp256
|
||||
| sym::bhp512
|
||||
| sym::bhp768
|
||||
| sym::bhp1024
|
||||
| sym::ped64
|
||||
| sym::ped128
|
||||
| sym::psd2
|
||||
| sym::psd4
|
||||
| sym::psd8 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
// /// Returns `true` if the given symbol matches the name of a core circuit.
|
||||
// pub fn is_core_circuit(circuit: Symbol) -> bool {
|
||||
// match circuit {
|
||||
// sym::bhp256
|
||||
// | sym::bhp512
|
||||
// | sym::bhp768
|
||||
// | sym::bhp1024
|
||||
// | sym::ped64
|
||||
// | sym::ped128
|
||||
// | sym::psd2
|
||||
// | sym::psd4
|
||||
// | sym::psd8 => true,
|
||||
// _ => false,
|
||||
// }
|
||||
// }
|
||||
|
||||
/// A core instruction that maps directly to an AVM bytecode instruction.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
|
@ -406,24 +406,26 @@ impl ParserContext<'_> {
|
||||
Some(Ok(gt))
|
||||
}
|
||||
|
||||
fn parse_circuit_member(&mut self) -> Result<CircuitVariableInitializer> {
|
||||
let identifier = self.expect_ident()?;
|
||||
let expression = if self.eat(&Token::Colon) {
|
||||
// Parse individual circuit variable declarations.
|
||||
Some(self.parse_expression()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(CircuitVariableInitializer { identifier, expression })
|
||||
}
|
||||
|
||||
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||
/// circuit initialization expression.
|
||||
/// let foo = Foo { x: 1u8 };
|
||||
pub fn parse_circuit_expression(&mut self, identifier: Identifier) -> Result<Expression> {
|
||||
let (members, _, span) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| {
|
||||
let expression = if p.eat(&Token::Colon) {
|
||||
// Parse individual circuit variable declarations.
|
||||
Some(p.parse_expression()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (members, _, end) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_circuit_member().map(Some))?;
|
||||
|
||||
Ok(Some(CircuitVariableInitializer {
|
||||
identifier: p.expect_ident()?,
|
||||
expression,
|
||||
}))
|
||||
})?;
|
||||
Ok(Expression::CircuitInit(CircuitInitExpression {
|
||||
span: &identifier.span + &span,
|
||||
span: identifier.span + end,
|
||||
name: identifier,
|
||||
members,
|
||||
}))
|
||||
@ -480,7 +482,7 @@ impl ParserContext<'_> {
|
||||
Token::StaticString(value) => Expression::Value(ValueExpression::String(value, span)),
|
||||
Token::Ident(name) => {
|
||||
let ident = Identifier { name, span };
|
||||
if !self.disallow_circuit_construction && self.eat(&Token::LeftCurly) {
|
||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||
self.parse_circuit_expression(ident)?
|
||||
} else {
|
||||
Expression::Identifier(ident)
|
||||
@ -491,7 +493,7 @@ impl ParserContext<'_> {
|
||||
name: sym::SelfUpper,
|
||||
span,
|
||||
};
|
||||
if !self.disallow_circuit_construction && self.eat(&Token::LeftCurly) {
|
||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||
self.parse_circuit_expression(ident)?
|
||||
} else {
|
||||
Expression::Identifier(ident)
|
||||
|
@ -163,8 +163,11 @@ impl ParserContext<'_> {
|
||||
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member function.
|
||||
pub fn parse_member_function_declaration(&mut self) -> Result<CircuitMember> {
|
||||
if self.peek_is_function() {
|
||||
// CAUTION: function members are unstable for testnet3.
|
||||
let function = self.parse_function()?;
|
||||
Ok(CircuitMember::CircuitFunction(Box::new(function.1)))
|
||||
|
||||
return Err(ParserError::circuit_functions_unstable(function.1.span()).into())
|
||||
// Ok(CircuitMember::CircuitFunction(Box::new(function.1)))
|
||||
} else {
|
||||
return Err(Self::unexpected_item(&self.token).into());
|
||||
}
|
||||
@ -246,7 +249,9 @@ impl ParserContext<'_> {
|
||||
|
||||
// Parse return type.
|
||||
self.expect(&Token::Arrow)?;
|
||||
self.disallow_circuit_construction = true;
|
||||
let output = self.parse_all_types()?.0;
|
||||
self.disallow_circuit_construction = false;
|
||||
|
||||
// Parse the function body.
|
||||
let block = self.parse_block()?;
|
||||
|
@ -47,4 +47,11 @@ impl<'a> ProgramVisitor<'a> for CreateSymbolTable<'a> {
|
||||
}
|
||||
VisitResult::SkipChildren
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, input: &'a Circuit) -> VisitResult {
|
||||
if let Err(err) = self.symbol_table.insert_circuit(input.name(), input) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
VisitResult::SkipChildren
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use leo_ast::Function;
|
||||
use leo_ast::{Circuit, Function};
|
||||
use leo_errors::{AstError, Result};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
@ -26,9 +26,12 @@ use crate::{VariableScope, VariableSymbol};
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct SymbolTable<'a> {
|
||||
/// Functions represents the name of each function mapped to the Ast's function definition.
|
||||
/// Maps function names to function definitions.
|
||||
/// This field is populated at a first pass.
|
||||
functions: IndexMap<Symbol, &'a Function>,
|
||||
/// Maps circuit names to circuit definitions.
|
||||
/// This field is populated at a first pass.
|
||||
circuits: IndexMap<Symbol, &'a Circuit>,
|
||||
/// Variables represents functions variable definitions and input variables.
|
||||
/// This field is not populated till necessary.
|
||||
pub(crate) variables: VariableScope<'a>,
|
||||
@ -54,6 +57,15 @@ impl<'a> SymbolTable<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_circuit(&mut self, symbol: Symbol, insert: &'a Circuit) -> Result<()> {
|
||||
if self.circuits.contains_key(&symbol) {
|
||||
// Return an error if the circuit name has already been inserted.
|
||||
return Err(AstError::shadowed_circuit(symbol, insert.span).into())
|
||||
}
|
||||
self.circuits.insert(symbol, insert);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_variable(&mut self, symbol: Symbol, insert: VariableSymbol<'a>) -> Result<()> {
|
||||
self.check_shadowing(&symbol, insert.span)?;
|
||||
self.variables.variables.insert(symbol, insert);
|
||||
@ -64,6 +76,10 @@ impl<'a> SymbolTable<'a> {
|
||||
self.functions.get(symbol)
|
||||
}
|
||||
|
||||
pub fn lookup_circuit(&self, symbol: &Symbol) -> Option<&&'a Circuit> {
|
||||
self.circuits.get(symbol)
|
||||
}
|
||||
|
||||
pub fn lookup_variable(&self, symbol: &Symbol) -> Option<&VariableSymbol<'a>> {
|
||||
self.variables.lookup_variable(symbol)
|
||||
}
|
||||
@ -91,6 +107,10 @@ impl<'a> Display for SymbolTable<'a> {
|
||||
write!(f, "{func}")?;
|
||||
}
|
||||
|
||||
for circ in self.circuits.values() {
|
||||
write!(f, "{circ}")?;
|
||||
}
|
||||
|
||||
write!(f, "{}", self.variables)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_core::is_core_circuit;
|
||||
use leo_errors::TypeCheckerError;
|
||||
|
||||
use crate::TypeChecker;
|
||||
@ -66,8 +65,8 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
|
||||
fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_identifier(input) {
|
||||
return if is_core_circuit(input.name) {
|
||||
Some(Type::Identifier(*input))
|
||||
return if let Some(circuit) = self.visitor.symbol_table.clone().lookup_circuit(&input.name) {
|
||||
Some(self.visitor.assert_expected_option(Type::Identifier(circuit.identifier.clone()), expected, circuit.span()))
|
||||
} else if let Some(var) = self.visitor.symbol_table.clone().lookup_variable(&input.name) {
|
||||
Some(self.visitor.assert_expected_option(*var.type_, expected, var.span))
|
||||
} else {
|
||||
@ -602,9 +601,45 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
_input: &'a CircuitInitExpression,
|
||||
_additional: &Self::AdditionalInput,
|
||||
input: &'a CircuitInitExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
unimplemented!("disable circuit inits for now")
|
||||
if let Some(circ) = self.visitor.symbol_table.clone().lookup_circuit(&input.name.name) {
|
||||
// Check circuit type name.
|
||||
let ret = self.visitor.assert_expected_circuit(circ.identifier, additional, input.name.span());
|
||||
|
||||
// Check number of circuit members.
|
||||
if circ.members.len() != input.members.len() {
|
||||
self.visitor.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_circuit_members(
|
||||
circ.members.len(),
|
||||
input.members.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
// Check circuit member types
|
||||
circ.members
|
||||
.iter()
|
||||
.zip(input.members.iter())
|
||||
.for_each(|(expected, actual)| {
|
||||
match expected {
|
||||
CircuitMember::CircuitVariable(_name, type_) => {
|
||||
if let Some(expr) = &actual.expression {
|
||||
self.visit_expression(expr, &Some(*type_));
|
||||
}
|
||||
}
|
||||
_ => {/* Circuit functions cannot be inside circuit init expressions */}
|
||||
}
|
||||
});
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,4 @@ impl<'a> ProgramVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, _input: &'a Circuit) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -98,9 +98,9 @@ impl<'a> TypeChecker<'a> {
|
||||
/// Emits an error if the given type conflicts with a core library type.
|
||||
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
||||
if let Some(Type::Identifier(ident)) = type_ {
|
||||
if !(self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name)) {
|
||||
if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_core_type(&ident.name, ident.span()).into());
|
||||
.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,6 +140,18 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `circuit` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_circuit(&mut self, circuit: Identifier, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(Type::Identifier(expected)) = expected {
|
||||
if expected.name != circuit.name {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span).into());
|
||||
}
|
||||
}
|
||||
|
||||
Type::Identifier(circuit)
|
||||
}
|
||||
|
||||
/// Returns the given `actual` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_option(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(expected) = expected {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
description = "Logs hello world"
|
||||
license = "LICENSE-MIT"
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
circuit Foo {
|
||||
x: u8,
|
||||
y: u8,
|
||||
}
|
||||
|
||||
function main(a: u8) -> field {
|
||||
return BHP257::hash(a);
|
||||
return BHP256::hash(a);
|
||||
}
|
1
examples/linear-regression/.gitignore
vendored
1
examples/linear-regression/.gitignore
vendored
@ -1 +0,0 @@
|
||||
outputs/
|
@ -1,12 +0,0 @@
|
||||
[project]
|
||||
name = "linear-regression"
|
||||
version = "0.1.0"
|
||||
description = "The linear-regression package"
|
||||
license = "MIT"
|
||||
|
||||
[remote]
|
||||
author = "aleo"
|
||||
|
||||
[target]
|
||||
curve = "bls12_377"
|
||||
proving_system = "groth16"
|
@ -1,20 +0,0 @@
|
||||
# linear-regression
|
||||
|
||||
## Build Guide
|
||||
|
||||
To compile this Leo program, run:
|
||||
```bash
|
||||
leo build
|
||||
```
|
||||
|
||||
To test this Leo program, run:
|
||||
```bash
|
||||
leo test
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
To output the number of constraints, run:
|
||||
```bash
|
||||
leo build -d
|
||||
```
|
@ -1,7 +0,0 @@
|
||||
// The program input for light-cuddly-cyan-polo/src/main.leo
|
||||
[main]
|
||||
x: i32 = 1i32;
|
||||
y: i32 = 2i32;
|
||||
|
||||
[registers]
|
||||
r0: [i32; 2] = [1i32, 2i32];
|
@ -1,26 +0,0 @@
|
||||
// The program state for linear-regression/src/main.leo
|
||||
[[public]]
|
||||
|
||||
[state]
|
||||
leaf_index: u32 = 0;
|
||||
root: [u8; 32] = [0; 32];
|
||||
|
||||
[[private]]
|
||||
|
||||
[record]
|
||||
serial_number: [u8; 64] = [0; 64];
|
||||
commitment: [u8; 32] = [0; 32];
|
||||
owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9;
|
||||
is_dummy: bool = false;
|
||||
value: u64 = 0;
|
||||
payload: [u8; 32] = [0; 32];
|
||||
birth_program_id: [u8; 48] = [0; 48];
|
||||
death_program_id: [u8; 48] = [0; 48];
|
||||
serial_number_nonce: [u8; 32] = [0; 32];
|
||||
commitment_randomness: [u8; 32] = [0; 32];
|
||||
|
||||
[state_leaf]
|
||||
path: [u8; 128] = [0; 128];
|
||||
memo: [u8; 32] = [0; 32];
|
||||
network_id: u8 = 0;
|
||||
leaf_randomness: [u8; 32] = [0; 32];
|
@ -1,65 +0,0 @@
|
||||
circuit Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
||||
function new(x: i32, y: i32) -> Self {
|
||||
return Self { x, y };
|
||||
}
|
||||
}
|
||||
|
||||
circuit LinearRegression {
|
||||
points: [Point; 5],
|
||||
|
||||
// Instantiates a linear regression circuit.
|
||||
function new(points: [Point; 5]) -> Self {
|
||||
return Self { points };
|
||||
}
|
||||
|
||||
// Return the slope of the linear regression.
|
||||
function slope(self) -> i32 {
|
||||
|
||||
let num_points = 5i32;
|
||||
// Calculate the sums.
|
||||
let x_sum = 0i32;
|
||||
let y_sum = 0i32;
|
||||
let xy_sum = 0i32;
|
||||
let x2_sum = 0i32;
|
||||
for i in 0..5 {
|
||||
x_sum += self.points[i].x;
|
||||
y_sum += self.points[i].y;
|
||||
xy_sum += self.points[i].x * self.points[i].y;
|
||||
x2_sum += self.points[i].x * self.points[i].x;
|
||||
}
|
||||
let numerator = (num_points * xy_sum) - (x_sum * y_sum);
|
||||
let denominator = (num_points * x2_sum) - (x_sum * x_sum);
|
||||
let slope = numerator / denominator;
|
||||
return slope;
|
||||
}
|
||||
// Return the offset of the linear regression.
|
||||
function offset(self, slope: i32) -> i32 {
|
||||
let num_points = 5i32;
|
||||
// Calculate the sum.
|
||||
let x_sum = 0i32;
|
||||
let y_sum = 0i32;
|
||||
for i in 0..5 {
|
||||
x_sum += self.points[i].x;
|
||||
y_sum += self.points[i].y;
|
||||
}
|
||||
return (y_sum - slope * x_sum) / num_points;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function main (x: i32, y: i32) -> [i32; 2] {
|
||||
let points: [Point; 5] = [
|
||||
Point{x: x + 1, y: y + 1},
|
||||
Point{x: x + 2, y: y + 2},
|
||||
Point{x: x + 3, y: y + 3},
|
||||
Point{x: x + 4, y: y + 4},
|
||||
Point{x: x + 5, y: y + 5}
|
||||
];
|
||||
let reg = LinearRegression::new(points);
|
||||
let slope = reg.slope();
|
||||
let offset = reg.offset(slope);
|
||||
return [slope, offset];
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
[project]
|
||||
name = "pedersen-hash"
|
||||
version = "0.1.0"
|
||||
description = "A 256bit hash function"
|
||||
license = "LICENSE-MIT"
|
||||
|
||||
[remote]
|
||||
author = "aleo"
|
||||
|
||||
[target]
|
||||
curve = "bls12_377"
|
||||
proving_system = "groth16"
|
@ -1 +0,0 @@
|
||||
# pedersen-hash
|
@ -1,8 +0,0 @@
|
||||
[main]
|
||||
hash_input: [bool; 256] = [true; 256];
|
||||
|
||||
[constants]
|
||||
parameters: [group; 256] = [1group; 256];
|
||||
|
||||
[registers]
|
||||
r0: group = (1, 0)group;
|
@ -1,25 +0,0 @@
|
||||
circuit PedersenHash {
|
||||
parameters: [group; 256];
|
||||
|
||||
// Instantiates a Pedersen hash circuit
|
||||
function new(parameters: [group; 256]) -> Self {
|
||||
return Self { parameters: parameters };
|
||||
}
|
||||
|
||||
function hash(self, bits: [bool; 256]) -> group {
|
||||
let digest: group = 0group;
|
||||
for i in 0..256 {
|
||||
if bits[i] {
|
||||
digest += self.parameters[i];
|
||||
}
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
}
|
||||
|
||||
// The 'pedersen-hash' main function.
|
||||
function main(hash_input: [bool; 256], const parameters: [group; 256]) -> group {
|
||||
const pedersen = PedersenHash::new(parameters);
|
||||
return pedersen.hash(hash_input);
|
||||
}
|
||||
|
2
examples/silly-sudoku/.gitignore
vendored
2
examples/silly-sudoku/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
outputs/
|
||||
/.leo
|
@ -1,12 +0,0 @@
|
||||
[project]
|
||||
name = "silly-sudoku"
|
||||
version = "0.1.3"
|
||||
description = "A simple Sudoku puzzle grid"
|
||||
license = "MIT"
|
||||
|
||||
[remote]
|
||||
author = "howard"
|
||||
|
||||
[target]
|
||||
curve = "bls12_377"
|
||||
proving_system = "groth16"
|
@ -1,23 +0,0 @@
|
||||
# silly-sudoku
|
||||
|
||||
A simple Sudoku puzzle grid in Leo.
|
||||
|
||||
## Walkthrough
|
||||
|
||||
Start by defining a puzzle grid:
|
||||
```
|
||||
[[0, 4, 6],
|
||||
[3, 0, 9],
|
||||
[7, 5, 0]]
|
||||
```
|
||||
We treat all 0's as empty cells in the grid.
|
||||
|
||||
Next, generate an answer and construct it as a puzzle grid solution:
|
||||
```
|
||||
[[8, 4, 6],
|
||||
[3, 1, 9],
|
||||
[7, 5, 2]]
|
||||
```
|
||||
|
||||
The SillySudoku circuit will proceed to verify that the solution grid matches the starting puzzle grid,
|
||||
and check that each number between 1 - 9 is used exactly once.
|
@ -1,12 +0,0 @@
|
||||
// The program input for tmp-test/src/main.leo
|
||||
[main]
|
||||
puzzle: [u8; (3, 3)] = [[0, 2, 0],
|
||||
[0, 0, 6],
|
||||
[0, 8, 9]];
|
||||
|
||||
answer: [u8; (3, 3)] = [[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]];
|
||||
|
||||
[registers]
|
||||
r: bool = false;
|
@ -1,26 +0,0 @@
|
||||
// The program state for tmp-test/src/main.leo
|
||||
[[public]]
|
||||
|
||||
[state]
|
||||
leaf_index: u32 = 0;
|
||||
root: [u8; 32] = [0; 32];
|
||||
|
||||
[[private]]
|
||||
|
||||
[record]
|
||||
serial_number: [u8; 64] = [0; 64];
|
||||
commitment: [u8; 32] = [0; 32];
|
||||
owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9;
|
||||
is_dummy: bool = false;
|
||||
value: u64 = 0;
|
||||
payload: [u8; 32] = [0; 32];
|
||||
birth_program_id: [u8; 48] = [0; 48];
|
||||
death_program_id: [u8; 48] = [0; 48];
|
||||
serial_number_nonce: [u8; 32] = [0; 32];
|
||||
commitment_randomness: [u8; 32] = [0; 32];
|
||||
|
||||
[state_leaf]
|
||||
path: [u8; 128] = [0; 128];
|
||||
memo: [u8; 32] = [0; 32];
|
||||
network_id: u8 = 0;
|
||||
leaf_randomness: [u8; 32] = [0; 32];
|
@ -1,14 +0,0 @@
|
||||
// The program input for tmp-test/src/main.leo
|
||||
[main]
|
||||
puzzle: [u8; (3, 3)] = [[1, 0, 5],
|
||||
[0, 2, 0],
|
||||
[7, 0, 0]];
|
||||
|
||||
answer: [u8; (3, 3)] = [[1, 4, 5],
|
||||
[3, 2, 6],
|
||||
[7, 8, 9]];
|
||||
|
||||
expected: bool = true;
|
||||
|
||||
[registers]
|
||||
r: bool = false;
|
@ -1,70 +0,0 @@
|
||||
/**
|
||||
* The SillySudoku circuit
|
||||
*
|
||||
* This circuit generates a silly Sudoku puzzle,
|
||||
* by constructing a 3x3 puzzle grid with some preset numbers 1-9,
|
||||
* and requiring an answer where each number is used exactly once.
|
||||
*
|
||||
* -----------
|
||||
* | 5 | 8 | 3 |
|
||||
* |-----------|
|
||||
* | 2 | 7 | 4 |
|
||||
* |-----------|
|
||||
* | 1 | 9 | 6 |
|
||||
* -----------
|
||||
*/
|
||||
circuit SillySudoku {
|
||||
// The starting grid values for the Sudoku puzzle.
|
||||
// Unset cells on the puzzle grid are set to 0.
|
||||
puzzle_grid: [u8; (3, 3)];
|
||||
|
||||
/**
|
||||
* Returns true if a given Sudoku answer is correct.
|
||||
*
|
||||
* Verifies a given answer by iterating through the Sudoku puzzle,
|
||||
* and checking that each number is set exactly once.
|
||||
*/
|
||||
function solve(self, answer: [u8; (3, 3)]) -> bool {
|
||||
// The result boolean is set to true, if the answer is correct.
|
||||
let result = true;
|
||||
// An array that tracks the numbers used on the Sudoku grid.
|
||||
let seen = [false; 9];
|
||||
|
||||
// Iterate through the Sudoku grid and check each cell.
|
||||
for i in 0..3 {
|
||||
for j in 0..3 {
|
||||
|
||||
// Fetch the current cell value for the Sudoku grid.
|
||||
let grid_value = self.puzzle_grid[i][j];
|
||||
|
||||
// Fetch the current cell value for the given answer.
|
||||
let answer_value = answer[i][j];
|
||||
|
||||
// Set the index by subtracting 1 from the answer value.
|
||||
let index = answer_value - 1;
|
||||
|
||||
// Check if this number has already been used on the grid.
|
||||
let already_seen: bool = seen[index];
|
||||
|
||||
// If this number is already used, the answer is incorrect.
|
||||
// Sets the result to false.
|
||||
if already_seen {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// If the cell is not empty, and the grid value doesn't match
|
||||
// the answer value, the answer is incorrect.
|
||||
// Sets the result to false.
|
||||
if (grid_value != 0 && grid_value != answer_value) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Sets the answer value as seen.
|
||||
seen[index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if all numbers 1-9 have been seen exactly once.
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import lib.SillySudoku;
|
||||
|
||||
// The `silly-sudoku` main function
|
||||
function main(puzzle: [u8; (3, 3)], answer: [u8; (3, 3)]) -> bool {
|
||||
console.log("Starting Sudoku solver...");
|
||||
console.log("{}", puzzle);
|
||||
|
||||
// Instantiate the Sudoku puzzle.
|
||||
let sudoku = SillySudoku { puzzle_grid: puzzle };
|
||||
|
||||
console.log("Checking Sudoku answer...");
|
||||
console.log("{}", answer);
|
||||
|
||||
// Evaluate the Sudoku puzzle with the given answer.
|
||||
let result = sudoku.solve(answer);
|
||||
|
||||
console.log("The answer is {}.", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Tests that the `silly-sudoku` circuit outputs true on a correct answer.
|
||||
@test
|
||||
function test_solve_pass() {
|
||||
let puzzle: [u8; (3, 3)] = [[0, 2, 0],
|
||||
[0, 0, 6],
|
||||
[0, 8, 9]];
|
||||
|
||||
let answer: [u8; (3, 3)] = [[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]];
|
||||
|
||||
// Runs the Sudoku checker.
|
||||
let result = main(puzzle, answer);
|
||||
|
||||
// Expects the result to be true.
|
||||
console.assert(true == result);
|
||||
}
|
||||
|
||||
// Tests that the `silly-sudoku` circuit outputs false on an incorrect answer.
|
||||
@test
|
||||
function test_solve_fail() {
|
||||
let puzzle: [u8; (3, 3)] = [[0, 2, 0],
|
||||
[0, 0, 6],
|
||||
[0, 8, 0]];
|
||||
|
||||
let answer: [u8; (3, 3)] = [[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 8]]; // We have an extra `8` in this column!
|
||||
|
||||
// Runs the Sudoku checker.
|
||||
let result = main(puzzle, answer);
|
||||
|
||||
// Expects the result to be false.
|
||||
console.assert(false == result);
|
||||
}
|
||||
|
||||
// Test that the `silly-sudoku` circuit outputs the expected value on a custom test input.
|
||||
@test(test_input)
|
||||
function test_solve_with_input(
|
||||
puzzle: [u8; (3, 3)],
|
||||
answer: [u8; (3, 3)],
|
||||
expected: bool
|
||||
) {
|
||||
// Runs the Sudoku checker.
|
||||
let result = main(puzzle, answer);
|
||||
|
||||
console.log("expected {}, got {}", expected, result);
|
||||
|
||||
console.assert(expected == result);
|
||||
}
|
11
examples/token/Leo.toml
Normal file
11
examples/token/Leo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "token"
|
||||
version = "0.3.0"
|
||||
description = "A simple token"
|
||||
license = "LICENSE-MIT"
|
||||
|
||||
[remote]
|
||||
author = "aleo"
|
||||
|
||||
[target]
|
||||
proving_system = "marlin"
|
3
examples/token/inputs/token.in
Normal file
3
examples/token/inputs/token.in
Normal file
@ -0,0 +1,3 @@
|
||||
[main]
|
||||
|
||||
[registers]
|
50
examples/token/src/main.leo
Normal file
50
examples/token/src/main.leo
Normal file
@ -0,0 +1,50 @@
|
||||
// CAUTION: Work in progress
|
||||
|
||||
circuit Token {
|
||||
// The token owner.
|
||||
owner: address,
|
||||
// The Aleo balance (in gates).
|
||||
balance: u64,
|
||||
// The token amount.
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
circuit Receiver {
|
||||
// The token owner.
|
||||
owner: Address,
|
||||
// The token amount.
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
function mint(r0: address, r1: u64) -> Token {
|
||||
return Token {
|
||||
owner: r0,
|
||||
balance: 0u64,
|
||||
amount: r1,
|
||||
};
|
||||
}
|
||||
|
||||
// The `transfer` function sends the specified number of tokens
|
||||
// to the receiver from the provided token record.
|
||||
function transfer(r0: Token, r1: Receiver) -> Token {
|
||||
// Checks the given token record has sufficient balance.
|
||||
// This `sub` operation is safe, and the proof will fail
|
||||
// if an overflow occurs. The output register `r2` holds
|
||||
// the change amount to be returned to the sender.
|
||||
let r2: u64 = r0.amount - r1.amount;
|
||||
|
||||
// Calls the `mint` function to produce a token record
|
||||
// for the specified receiver.
|
||||
let r3: Token = mint(r1.owner, r1.amount);
|
||||
|
||||
// Calls the `mint` function to produce a token record
|
||||
// with the change amount for the sender.
|
||||
let r4: Token = mint(r0.owner, r0.amount);
|
||||
|
||||
// return (r3, r4);
|
||||
return r3
|
||||
}
|
||||
|
||||
function main() -> u8 {
|
||||
return 1u8;
|
||||
}
|
@ -147,6 +147,14 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when a user shadows a circuit.
|
||||
@formatted
|
||||
shadowed_circuit {
|
||||
args: (circ: impl Display),
|
||||
msg: format!("circuit `{circ}` shadowed by"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when a user shadows a variable.
|
||||
@formatted
|
||||
shadowed_variable {
|
||||
|
@ -374,4 +374,12 @@ create_messages!(
|
||||
msg: "Arbitrary methods calls are not supported. Only special ones are.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Circuit functions are unstable in testnet3.
|
||||
@formatted
|
||||
circuit_functions_unstable {
|
||||
args: (),
|
||||
msg: "Circuit functions are currently an unstable feature and are disabled in Leo for testnet3",
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -153,12 +153,12 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when an invalid core type is used.
|
||||
/// For when a circuit is created with the same name as a core type.
|
||||
@formatted
|
||||
invalid_core_type {
|
||||
core_type_name_conflict {
|
||||
args: (type_: impl Display),
|
||||
msg: format!(
|
||||
"The type {type_} is not a valid core type.",
|
||||
"The type {type_} is a reserved core type name.",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
@ -172,4 +172,14 @@ create_messages!(
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries initialize a circuit with the incorrect number of args.
|
||||
@formatted
|
||||
incorrect_num_circuit_members {
|
||||
args: (expected: impl Display, received: impl Display),
|
||||
msg: format!(
|
||||
"Circuit expected `{expected}` members, but got `{received}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user