Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Some "interesting" Leo programs
# A tour of Leo by example

Add yours by making a PR!
## Concepts

- **Testing**: `example_with_test`
- **Modules**: `calculator`
- **Upgradability** `upgrades`
- **Const Generics**: `calculator`

5 changes: 5 additions & 0 deletions calculator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
*.avm
*.prover
*.verifier
outputs/
654 changes: 654 additions & 0 deletions calculator/build/main.aleo

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions calculator/build/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"program": "calculator.aleo",
"version": "0.1.0",
"description": "",
"license": "",
"leo": "3.1.0",
"dependencies": null,
"dev_dependencies": null
}
8 changes: 8 additions & 0 deletions calculator/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"program": "calculator.aleo",
"version": "0.1.0",
"description": "",
"license": "MIT",
"dependencies": null,
"dev_dependencies": null
}
67 changes: 67 additions & 0 deletions calculator/src/calculator.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// A programmable calculator.
struct Calculator::[N: u32] {
// The registers.
registers: registers::Registers::[N],
// The history.
// TODO: Make history longer.
history: history::History::[2 * N],
}

// Initialize the calculator.
inline init::[N: u32]() -> Calculator::[N] {
return Calculator::[N] {
registers: registers::init::[N](),
history: history::init::[2 * N]()
};
}

// Executes a sequence of instructions.
inline execute::[N: u32](
c: Calculator::[N],
instructions: [history::instruction::Instruction; N]
) -> Calculator::[N] {
for i in 0u32..N {
c = exec::[N](c, instructions[i]);
}
return c;
}

// Returns a transcript of the history.
inline transcript::[N: u32](c: Calculator::[N]) -> history::Transcript::[2 * N] {
return history::transcript::[2 * N](c.history);
}

// Executes a single instruction.
inline exec::[N: u32](
c: Calculator::[N],
i: history::instruction::Instruction,
) -> Calculator::[N] {
// Handle NOOP.
if i.opcode == history::instruction::opcodes::NOOP {
return c;
}

// Load the operands.
let op0 = registers::load::[N](c.registers, i.op0);
let op1 = registers::load::[N](c.registers, i.op1);

// Evaluate the operands.
let result = 0u32;
if i.opcode == history::instruction::opcodes::ADD {
result = math::add(op0, op1);
} else if i.opcode == history::instruction::opcodes::SUB {
result = math::sub(op0, op1);
} else if i.opcode == history::instruction::opcodes::MUL {
result = math::mul(op0, op1);
} else if i.opcode == history::instruction::opcodes::DIV {
result = math::div(op0, op1);
} else {
assert(false);
}

// Store the result.
c.registers = registers::store::[N](c.registers, i.d0, result);

// Return the updated calculator.
return c;
}
55 changes: 55 additions & 0 deletions calculator/src/calculator/history.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// A finite history of past instructions.
struct History::[N: u32] {
// The total number of instructions.
total: u32,
// The head of the buffer.
head: u32,
// The entries.
entries: [instruction::Instruction; N],
}

// A transcript of the history in order from newest to oldest.
struct Transcript::[N: u32] {
// The total number of instructions.
total: u32,
// The entries in order.
entries: [instruction::Instruction; N]
}

// Initializes a `History` object.
inline init::[N: u32]() -> History::[N] {
return History::[N] {
total: 0,
head: 0,
entries: [instruction::noop(); N],
};
}

// Adds an instruction to the history.
inline push::[N: u32](history: History::[N], instruction: instruction::Instruction) -> History::[N] {
// Add the instruction.
history.entries[history.head] = instruction;
// Increment the total.
history.total += 1;
// Increment the head.
history.head = history.head.add_wrapped(1) % N;
// Return the updated history.
return history;
}

// Returns the transcript.
inline transcript::[N: u32](history: History::[N]) -> Transcript::[N] {
// Initialize dummy entries.
let entries = [instruction::noop(); N];
// Update the entries.
for i in 0u32..N {
entries[i] = history.entries[i.sub_wrapped(1) % N];
}
// Return the transcript.
return Transcript::[N] {
total: history.total,
entries
};

}

67 changes: 67 additions & 0 deletions calculator/src/calculator/history/instruction.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// An instruction to execute on the calculator.
// Note: Negative values indicate a regsiter.
// There are 32 valid registers. (-1, ..., -32)
struct Instruction {
opcode: u8,
// An operand.
op0: i64,
// An operand.
op1: i64,
// A destination register.
d0: i64,
}

// Creates an instruction.
inline init(opcode: u8, op0: i64, op1: i64, d0: i64) -> Instruction {
assert(opcodes::opcode_is_valid(opcode));
assert(operand_is_valid(op0));
assert(operand_is_valid(op1));
assert(destination_is_valid(d0));
return Instruction {
opcode,
op0,
op1,
d0
};
}

// Createa a `NOOP` instruction.
inline noop() -> Instruction {
return init(opcodes::NOOP, 0, 0, 0);
}

// Creates a `ADD` instruction.
inline add(r0: i64, r1: i64, d0: i64) -> Instruction {
return init(opcodes::ADD, r0, r1, d0);
}

// Creates a `SUB` instruction.
inline sub(r0: i64, r1: i64, d0: i64) -> Instruction {
return init(opcodes::SUB, r0, r1, d0);
}

// Creates a `MUL` instruction.
inline mul(r0: i64, r1: i64, d0: i64) -> Instruction {
return init(opcodes::MUL, r0, r1, d0);
}

// Creates a `DIV` instruction.
inline div(r0: i64, r1: i64, d0: i64) -> Instruction {
return init(opcodes::DIV, r0, r1, d0);
}


// Returns whether an operand is valid.
inline operand_is_valid(op: i64) -> bool {
return op >= -32i64;
}

// Returns whether a destination register is valid.
inline destination_is_valid(d: i64) -> bool {
return d < 0 && d >= -32i64;
}





26 changes: 26 additions & 0 deletions calculator/src/calculator/history/instruction/opcodes.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// NOOP
const NOOP: u8 = 0;

// ADD
const ADD: u8 = 1;

// SUB
const SUB: u8 = 2;

// MUL
const MUL: u8 = 3;

// DIV
const DIV: u8 = 4;

// Returns whether an opcode is valid.
inline opcode_is_valid(opcode: u8) -> bool {
return opcode == 0u8
|| opcode == 1u8
|| opcode == 2u8
|| opcode == 3u8
|| opcode == 4u8;

}


24 changes: 24 additions & 0 deletions calculator/src/calculator/math.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Implements addition.
inline add(op0: u32, op1: u32) -> u32 {
return op0 + op1;
}

// Implements subtraction.
inline sub(op0: u32, op1: u32) -> u32 {
return op0 - op1;
}

// Implements multiplication.
inline mul(op0: u32, op1: u32) -> u32 {
return op0 * op1;
}

// Implements division.
inline div(op0: u32, op1: u32) -> u32 {
return op0 / op1;
}





52 changes: 52 additions & 0 deletions calculator/src/calculator/registers.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// A register file.
struct Registers::[N: u32] {
r: [u32; N],
}

// Initializes a register file.
inline init::[N: u32]() -> Registers::[N] {
return Registers::[N] {
r: [0u32; N],
};
}

// Loads an operand.
inline load::[N: u32](registers: Registers::[N], op: i64) -> u32 {
// Initialize the result.
let result = op;
// Iterate through the registers and check for a match.
for i in 0u32..N {
let id: i64 = index_to_id(i);
if op == id {
result = registers.r[i] as i64;
}
}
// Cast the result to a `u32`` and return it.
return (result as u32);
}

// Stores a value into a register.
inline store::[N: u32](registers: Registers::[N], d: i64, v: u32) -> Registers::[N] {
// Get the register index.
let index = id_to_index::[N](d);
// Iterate through the registers and set the appropriate one.
for i in 0u32..N {
if index == i {
registers.r[i] = v;
}
}
// Return the updated registers.
return registers;
}


// Convert a register index into its ID.
inline index_to_id(i: u32) -> i64 {
return -(i as i64 + 1);
}

// Convert a register ID into an index, checking for validity.
inline id_to_index::[N: u32](id: i64) -> u32 {
assert(id < 0 && id >= -(N as i64));
return (id + 1) as u32;
}
25 changes: 25 additions & 0 deletions calculator/src/main.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// The 'calculator' program.
program calculator.aleo {
@noupgrade
async constructor() {}

const SIZE: u32 = 4;

transition init() -> calculator::Calculator::[SIZE] {
return calculator::init::[SIZE]();
}

transition execute(
c: calculator::Calculator::[SIZE],
instructions: [calculator::history::instruction::Instruction; SIZE],
) -> calculator::Calculator::[SIZE] {
return calculator::execute::[SIZE](c, instructions);
}

transition transcript(
c: calculator::Calculator::[SIZE]
) -> calculator::history::Transcript::[2 * SIZE] {
return calculator::transcript::[SIZE](c);
}

}
18 changes: 18 additions & 0 deletions calculator/tests/test_modules.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import calculator.aleo;
program test_calculcator.aleo {
@test
script test_it() {
let result: u32 = calculator.aleo/main(1u32, 2u32);
assert_eq(result, 3u32);
}

@test
@should_fail
transition do_nothing() {
let result: u32 = calculator.aleo/main(2u32, 3u32);
assert_eq(result, 3u32);
}

@noupgrade
async constructor() {}
}