mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-21 18:05:30 +03:00
Remove examples and add it back in as a submodule
This commit is contained in:
parent
b391f51250
commit
d2de53e86e
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "examples"]
|
||||
path = examples
|
||||
url = https://github.com/ProvableHQ/leo-examples
|
1
examples
Submodule
1
examples
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b742a2f93b7ec6b4f23f52cbe25333b9a7f1d7ca
|
@ -1,26 +0,0 @@
|
||||
# Leo Examples
|
||||
|
||||
This directory includes the following Leo code including:
|
||||
|
||||
1. Hello World -> Basic Sum of two u32
|
||||
2. Groups -> Basic operations over groups
|
||||
3. Core -> Core functions over a field type
|
||||
4. Bubblesort -> Sorting algorithms over a tuple
|
||||
5. Message -> Initialization of a struct
|
||||
6. Token -> Record example
|
||||
|
||||
along with many more.
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run each program, run:
|
||||
```bash
|
||||
leo run main <inputs>
|
||||
```
|
||||
|
||||
## Execute Guide
|
||||
|
||||
To execute each program call, run:
|
||||
```bash
|
||||
leo execute main <inputs>
|
||||
```
|
@ -1,4 +0,0 @@
|
||||
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
4
examples/auction/.gitignore
vendored
4
examples/auction/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,57 +0,0 @@
|
||||
<!-- # 🏛️ Blind Auction -->
|
||||
|
||||
[//]: # (<img alt="workshop/auction" width="1412" src="../.resources/auction.png">)
|
||||
|
||||
A first-price sealed-bid auction in Leo.
|
||||
|
||||
## Summary
|
||||
|
||||
A first-price sealed-bid auction (or blind auction) is a type of auction in which each participant submits a bid without knowing the bids of the other participants.
|
||||
The bidder with the highest bid wins the auction.
|
||||
|
||||
In this model, there are two parties: the auctioneer and the bidders.
|
||||
- **Bidder**: A participant in the auction.
|
||||
- **Auctioneer**: The party responsible for conducting the auction.
|
||||
|
||||
We make the following assumptions about the auction:
|
||||
- The auctioneer is honest. That is, the auctioneer will resolve **all** bids in the order they are received. The auctioneer will not tamper with the bids.
|
||||
- There is no limit to the number of bids.
|
||||
- The auctioneer knows the identity of all bidders, but bidders do not necessarily know the identity of other bidders.
|
||||
|
||||
Under this model, we require that:
|
||||
- Bidders do not learn any information about the value of other bids.
|
||||
|
||||
### Auction Flow
|
||||
The auction is conducted in a series of stages.
|
||||
- **Bidding**: In the bidding stage, bidders submit bids to the auctioneer. They do so by invoking the `place_bid` function.
|
||||
- **Resolution**: In the resolution stage, the auctioneer resolves the bids in the order they were received. The auctioneer does so by invoking the `resolve` function. The resolution process produces a single winning bid.
|
||||
- **Finishing**: In this stage, the auctioneer finishes the auction by invoking the `finish` function. This function returns the winning bid to the bidder, which the bidder can then use to claim the item.
|
||||
|
||||
|
||||
## Language Features and Concepts
|
||||
- `record` declarations
|
||||
- `assert_eq`
|
||||
- record ownership
|
||||
|
||||
## Running the Program
|
||||
|
||||
Leo provides users with a command line interface for compiling and running Leo programs.
|
||||
|
||||
### Configuring Accounts
|
||||
The `.env` file contains a private key.
|
||||
This is the account that will be used to sign transactions and is checked for record ownership.
|
||||
When executing programs as different parties, be sure to set the `PRIVATE_KEY` field in `.env` to the appropriate values.
|
||||
See `./run.sh` for an example of how to run the program as different parties.
|
||||
|
||||
|
||||
The [Aleo SDK](https://github.com/ProvableHQ/leo/tree/mainnet) provides an interface for generating new accounts.
|
||||
To generate a new account, navigate to [provable.tools](https://provable.tools).
|
||||
|
||||
|
||||
### Providing inputs via the command line.
|
||||
```bash
|
||||
leo run <function_name> <input_1> <input_2> ...
|
||||
```
|
||||
See `./run.sh` for an example.
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
program auction.aleo;
|
||||
|
||||
record Bid:
|
||||
owner as address.private;
|
||||
bidder as address.private;
|
||||
amount as u64.private;
|
||||
is_winner as boolean.private;
|
||||
|
||||
|
||||
function place_bid:
|
||||
input r0 as address.private;
|
||||
input r1 as u64.private;
|
||||
assert.eq self.caller r0;
|
||||
cast aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg r0 r1 false into r2 as Bid.record;
|
||||
output r2 as Bid.record;
|
||||
|
||||
|
||||
function resolve:
|
||||
input r0 as Bid.record;
|
||||
input r1 as Bid.record;
|
||||
assert.eq self.caller aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg;
|
||||
gte r0.amount r1.amount into r2;
|
||||
ternary r2 r0.owner r1.owner into r3;
|
||||
ternary r2 r0.bidder r1.bidder into r4;
|
||||
ternary r2 r0.amount r1.amount into r5;
|
||||
ternary r2 r0.is_winner r1.is_winner into r6;
|
||||
cast r3 r4 r5 r6 into r7 as Bid.record;
|
||||
output r7 as Bid.record;
|
||||
|
||||
|
||||
function finish:
|
||||
input r0 as Bid.record;
|
||||
assert.eq self.caller aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg;
|
||||
cast r0.bidder r0.bidder r0.amount true into r1 as Bid.record;
|
||||
output r1 as Bid.record;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "auction.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "auction.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
#!/bin/bash
|
||||
# First check that Leo is installed.
|
||||
if ! command -v leo &> /dev/null
|
||||
then
|
||||
echo "leo is not installed."
|
||||
exit
|
||||
fi
|
||||
|
||||
# The private key and address of the first bidder.
|
||||
# Swap these into program.json, when running transactions as the first bidder.
|
||||
# NETWORK=testnet
|
||||
# PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
|
||||
# The private key and address of the second bidder.
|
||||
# Swap these into program.json, when running transactions as the second bidder.
|
||||
# NETWORK=testnet
|
||||
# PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
|
||||
|
||||
# The private key and address of the auctioneer.
|
||||
# Swap these into program.json, when running transactions as the auctioneer.
|
||||
# NETWORK=testnet
|
||||
# PRIVATE_KEY=APrivateKey1zkp2GUmKbVsuc1NSj28pa1WTQuZaK5f1DQJAT6vPcHyWokG
|
||||
|
||||
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 0: Initialize a new 2-party auction ########
|
||||
######## ########
|
||||
######## ------------------------------- ########
|
||||
######## | OPEN | A | B | ########
|
||||
######## ------------------------------- ########
|
||||
######## | Bid | | | ########
|
||||
######## ------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
# Swap in the private key and address of the first bidder to .env.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
# Have the first bidder place a bid of 10.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 1: The first bidder places a bid of 10 ########
|
||||
######## ########
|
||||
######## ------------------------------- ########
|
||||
######## | OPEN | A | B | ########
|
||||
######## ------------------------------- ########
|
||||
######## | Bid | 10 | | ########
|
||||
######## ------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run place_bid aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px 10u64 || exit
|
||||
|
||||
# Swap in the private key and address of the second bidder to .env.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
# Have the second bidder place a bid of 90.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 2: The second bidder places a bid of 90 ########
|
||||
######## ########
|
||||
######## ------------------------------- ########
|
||||
######## | OPEN | A | B | ########
|
||||
######## ------------------------------- ########
|
||||
######## | Bid | 10 | 90 | ########
|
||||
######## ------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run place_bid aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t 90u64 || exit
|
||||
|
||||
# Swap in the private key and address of the auctioneer to .env.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2GUmKbVsuc1NSj28pa1WTQuZaK5f1DQJAT6vPcHyWokG
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
# Have the auctioneer select the winning bid.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 3: The auctioneer selects the winning bidder ########
|
||||
######## ########
|
||||
######## ------------------------------- ########
|
||||
######## | OPEN | A | → B ← | ########
|
||||
######## ------------------------------- ########
|
||||
######## | Bid | 10 | → 90 ← | ########
|
||||
######## ------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run resolve "{
|
||||
owner: aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg.private,
|
||||
bidder: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
amount: 10u64.private,
|
||||
is_winner: false.private,
|
||||
_nonce: 4668394794828730542675887906815309351994017139223602571716627453741502624516group.public
|
||||
}" "{
|
||||
owner: aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg.private,
|
||||
bidder: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
amount: 90u64.private,
|
||||
is_winner: false.private,
|
||||
_nonce: 5952811863753971450641238938606857357746712138665944763541786901326522216736group.public
|
||||
}" || exit
|
||||
|
||||
# Have the auctioneer finish the auction.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 4: The auctioneer completes the auction. ########
|
||||
######## ########
|
||||
######## ------------------------------- ########
|
||||
######## | CLOSE | A | → B ← | ########
|
||||
######## ------------------------------- ########
|
||||
######## | Bid | 10 | → 90 ← | ########
|
||||
######## ------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run finish "{
|
||||
owner: aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg.private,
|
||||
bidder: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
amount: 90u64.private,
|
||||
is_winner: false.private,
|
||||
_nonce: 5952811863753971450641238938606857357746712138665944763541786901326522216736group.public
|
||||
}" || exit
|
||||
|
||||
|
||||
# Restore the .env file to its original state.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,66 +0,0 @@
|
||||
program auction.aleo {
|
||||
// A bid in an auction.
|
||||
// - `owner` : The address of the account that owns the record associated with this bid.
|
||||
// This is separate from the address of the account that placed the bid.
|
||||
// - `bidder` : The address of the account that placed the bid.
|
||||
// - `amount` : The amount of the bid.
|
||||
// - `is_winner` : Whether the bid is the winning bid.
|
||||
record Bid {
|
||||
owner: address,
|
||||
bidder: address,
|
||||
amount: u64,
|
||||
is_winner: bool,
|
||||
}
|
||||
|
||||
// Returns a new bid.
|
||||
// - `bidder` : The address of the account that placed the bid.
|
||||
// - `amount` : The amount of the bid.
|
||||
// Requires that `bidder` matches the function caller.
|
||||
// The owner of the record is set to the entity responsible for running the auction (auction runner).
|
||||
// The address of the auction runner is aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg.
|
||||
transition place_bid(bidder: address, amount: u64) -> Bid {
|
||||
// Ensure the caller is the auction bidder.
|
||||
assert_eq(self.caller, bidder);
|
||||
// Return a new 'Bid' record for the auction bidder.
|
||||
return Bid {
|
||||
owner: aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg,
|
||||
bidder: bidder,
|
||||
amount: amount,
|
||||
is_winner: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Returns the winning bid.
|
||||
// - `first` : The first bid.
|
||||
// - `second` : The second bid.
|
||||
// Requires that the function caller is the auction runner.
|
||||
// Assumes that the function is invoked only after the bidding period has ended.
|
||||
// In the event of a tie, the first bid is selected.
|
||||
transition resolve(first: Bid, second: Bid) -> Bid {
|
||||
// Ensure the caller is the auctioneer.
|
||||
assert_eq(self.caller, aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg);
|
||||
// Resolve the winner of the auction.
|
||||
if (first.amount >= second.amount) {
|
||||
return first;
|
||||
} else {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns ownership of the bid to bidder.
|
||||
// - `bid` : The winning bid.
|
||||
// Requires that the function caller is the auction runner.
|
||||
// Assumes that the function is invoked only after all bids have been resolved.
|
||||
transition finish(bid: Bid) -> Bid {
|
||||
// Ensure the caller is the auctioneer.
|
||||
assert_eq(self.caller, aleo1ashyu96tjwe63u0gtnnv8z5lhapdu4l5pjsl2kha7fv7hvz2eqxs5dz0rg);
|
||||
// Return 'is_winner' as 'true' in the winning 'Bid'.
|
||||
return Bid {
|
||||
owner: bid.bidder,
|
||||
bidder: bid.bidder,
|
||||
amount: bid.amount,
|
||||
is_winner: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
4
examples/basic_bank/.gitignore
vendored
4
examples/basic_bank/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,55 +0,0 @@
|
||||
<!-- # 🏦 Basic Bank -->
|
||||
|
||||
[//]: # (<img alt="workshop/basic_bank" width="1412" src="../.resources/basic_bank.png">)
|
||||
|
||||
A simple-interest yielding bank account in Leo.
|
||||
|
||||
## Summary
|
||||
|
||||
This program implements a bank that issues tokens to users and allows users to deposit tokens to accrue simple interest on their deposits.
|
||||
|
||||
### User Flow
|
||||
1. The bank issues users tokens via the `issue` function.
|
||||
2. A user deposits tokens via the `deposit` function.
|
||||
3. Upon a user's request to withdraw, the bank calculates the appropriate amount of compound interest and pays the user the principal and interest via the `withdraw` function.
|
||||
|
||||
Note that the program can be easily extended to include additional features such as a `transfer` function, which would allow users to transfer tokens to other users.
|
||||
|
||||
## Bugs
|
||||
|
||||
You may have already guessed that this program has a few bugs. We list some of them below:
|
||||
- `withdraw` can only be invoked by the bank. A malicious bank could lock users' tokens by not invoking `withdraw`.
|
||||
- `withdraw` fails if the sum of the interest and principal is greater than the user's balance.
|
||||
- Users can increase their principal by depositing tokens multiple times, including immediately before withdrawal.
|
||||
- Integer division rounds down; if the calculated interest is too small, then it will be rounded down to zero.
|
||||
|
||||
Can you find any others?
|
||||
|
||||
## Language Features and Concepts
|
||||
- `record` declarations
|
||||
- `assert_eq`
|
||||
- core functions, e.g. `BHP256::hash_to_field`
|
||||
- record ownership
|
||||
- loops and bounded iteration
|
||||
- mappings
|
||||
- `async`/`await`
|
||||
|
||||
## Running the Program
|
||||
|
||||
Leo provides users with a command line interface for compiling and running Leo programs.
|
||||
|
||||
### Configuring Accounts
|
||||
The `.env` file contains a private key.
|
||||
This is the account that will be used to sign transactions and is checked for record ownership.
|
||||
When executing programs as different parties, be sure to set the `PRIVATE_KEY` field in `.env` to the appropriate values.
|
||||
See `./run.sh` for an example of how to run the program as different parties.
|
||||
|
||||
|
||||
The [Aleo SDK](https://github.com/ProvableHQ/leo/tree/mainnet) provides an interface for generating new accounts.
|
||||
To generate a new account, navigate to [provable.tools](https://provable.tools).
|
||||
|
||||
### Providing inputs via the command line.
|
||||
```bash
|
||||
leo run <function_name> <input_1> <input_2> ...
|
||||
```
|
||||
See `./run.sh` for an example.
|
@ -1,567 +0,0 @@
|
||||
program basic_bank.aleo;
|
||||
|
||||
record Token:
|
||||
owner as address.private;
|
||||
amount as u64.private;
|
||||
|
||||
|
||||
mapping balances:
|
||||
key as field.public;
|
||||
value as u64.public;
|
||||
|
||||
function issue:
|
||||
input r0 as address.private;
|
||||
input r1 as u64.private;
|
||||
assert.eq self.caller aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px;
|
||||
cast r0 r1 into r2 as Token.record;
|
||||
output r2 as Token.record;
|
||||
|
||||
|
||||
|
||||
function deposit:
|
||||
input r0 as Token.record;
|
||||
input r1 as u64.private;
|
||||
sub r0.amount r1 into r2;
|
||||
cast r0.owner r2 into r3 as Token.record;
|
||||
hash.bhp256 r0.owner into r4 as field;
|
||||
async deposit r4 r1 into r5;
|
||||
output r3 as Token.record;
|
||||
output r5 as basic_bank.aleo/deposit.future;
|
||||
|
||||
finalize deposit:
|
||||
input r0 as field.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use balances[r0] 0u64 into r2;
|
||||
add r2 r1 into r3;
|
||||
set r3 into balances[r0];
|
||||
|
||||
|
||||
|
||||
closure calculate_interest:
|
||||
input r0 as u64;
|
||||
input r1 as u64;
|
||||
input r2 as u64;
|
||||
lt 0u64 r2 into r3;
|
||||
mul r0 r1 into r4;
|
||||
div r4 10000u64 into r5;
|
||||
add r0 r5 into r6;
|
||||
ternary r3 r6 r0 into r7;
|
||||
lt 1u64 r2 into r8;
|
||||
mul r7 r1 into r9;
|
||||
div r9 10000u64 into r10;
|
||||
add r7 r10 into r11;
|
||||
ternary r8 r11 r7 into r12;
|
||||
lt 2u64 r2 into r13;
|
||||
mul r12 r1 into r14;
|
||||
div r14 10000u64 into r15;
|
||||
add r12 r15 into r16;
|
||||
ternary r13 r16 r12 into r17;
|
||||
lt 3u64 r2 into r18;
|
||||
mul r17 r1 into r19;
|
||||
div r19 10000u64 into r20;
|
||||
add r17 r20 into r21;
|
||||
ternary r18 r21 r17 into r22;
|
||||
lt 4u64 r2 into r23;
|
||||
mul r22 r1 into r24;
|
||||
div r24 10000u64 into r25;
|
||||
add r22 r25 into r26;
|
||||
ternary r23 r26 r22 into r27;
|
||||
lt 5u64 r2 into r28;
|
||||
mul r27 r1 into r29;
|
||||
div r29 10000u64 into r30;
|
||||
add r27 r30 into r31;
|
||||
ternary r28 r31 r27 into r32;
|
||||
lt 6u64 r2 into r33;
|
||||
mul r32 r1 into r34;
|
||||
div r34 10000u64 into r35;
|
||||
add r32 r35 into r36;
|
||||
ternary r33 r36 r32 into r37;
|
||||
lt 7u64 r2 into r38;
|
||||
mul r37 r1 into r39;
|
||||
div r39 10000u64 into r40;
|
||||
add r37 r40 into r41;
|
||||
ternary r38 r41 r37 into r42;
|
||||
lt 8u64 r2 into r43;
|
||||
mul r42 r1 into r44;
|
||||
div r44 10000u64 into r45;
|
||||
add r42 r45 into r46;
|
||||
ternary r43 r46 r42 into r47;
|
||||
lt 9u64 r2 into r48;
|
||||
mul r47 r1 into r49;
|
||||
div r49 10000u64 into r50;
|
||||
add r47 r50 into r51;
|
||||
ternary r48 r51 r47 into r52;
|
||||
lt 10u64 r2 into r53;
|
||||
mul r52 r1 into r54;
|
||||
div r54 10000u64 into r55;
|
||||
add r52 r55 into r56;
|
||||
ternary r53 r56 r52 into r57;
|
||||
lt 11u64 r2 into r58;
|
||||
mul r57 r1 into r59;
|
||||
div r59 10000u64 into r60;
|
||||
add r57 r60 into r61;
|
||||
ternary r58 r61 r57 into r62;
|
||||
lt 12u64 r2 into r63;
|
||||
mul r62 r1 into r64;
|
||||
div r64 10000u64 into r65;
|
||||
add r62 r65 into r66;
|
||||
ternary r63 r66 r62 into r67;
|
||||
lt 13u64 r2 into r68;
|
||||
mul r67 r1 into r69;
|
||||
div r69 10000u64 into r70;
|
||||
add r67 r70 into r71;
|
||||
ternary r68 r71 r67 into r72;
|
||||
lt 14u64 r2 into r73;
|
||||
mul r72 r1 into r74;
|
||||
div r74 10000u64 into r75;
|
||||
add r72 r75 into r76;
|
||||
ternary r73 r76 r72 into r77;
|
||||
lt 15u64 r2 into r78;
|
||||
mul r77 r1 into r79;
|
||||
div r79 10000u64 into r80;
|
||||
add r77 r80 into r81;
|
||||
ternary r78 r81 r77 into r82;
|
||||
lt 16u64 r2 into r83;
|
||||
mul r82 r1 into r84;
|
||||
div r84 10000u64 into r85;
|
||||
add r82 r85 into r86;
|
||||
ternary r83 r86 r82 into r87;
|
||||
lt 17u64 r2 into r88;
|
||||
mul r87 r1 into r89;
|
||||
div r89 10000u64 into r90;
|
||||
add r87 r90 into r91;
|
||||
ternary r88 r91 r87 into r92;
|
||||
lt 18u64 r2 into r93;
|
||||
mul r92 r1 into r94;
|
||||
div r94 10000u64 into r95;
|
||||
add r92 r95 into r96;
|
||||
ternary r93 r96 r92 into r97;
|
||||
lt 19u64 r2 into r98;
|
||||
mul r97 r1 into r99;
|
||||
div r99 10000u64 into r100;
|
||||
add r97 r100 into r101;
|
||||
ternary r98 r101 r97 into r102;
|
||||
lt 20u64 r2 into r103;
|
||||
mul r102 r1 into r104;
|
||||
div r104 10000u64 into r105;
|
||||
add r102 r105 into r106;
|
||||
ternary r103 r106 r102 into r107;
|
||||
lt 21u64 r2 into r108;
|
||||
mul r107 r1 into r109;
|
||||
div r109 10000u64 into r110;
|
||||
add r107 r110 into r111;
|
||||
ternary r108 r111 r107 into r112;
|
||||
lt 22u64 r2 into r113;
|
||||
mul r112 r1 into r114;
|
||||
div r114 10000u64 into r115;
|
||||
add r112 r115 into r116;
|
||||
ternary r113 r116 r112 into r117;
|
||||
lt 23u64 r2 into r118;
|
||||
mul r117 r1 into r119;
|
||||
div r119 10000u64 into r120;
|
||||
add r117 r120 into r121;
|
||||
ternary r118 r121 r117 into r122;
|
||||
lt 24u64 r2 into r123;
|
||||
mul r122 r1 into r124;
|
||||
div r124 10000u64 into r125;
|
||||
add r122 r125 into r126;
|
||||
ternary r123 r126 r122 into r127;
|
||||
lt 25u64 r2 into r128;
|
||||
mul r127 r1 into r129;
|
||||
div r129 10000u64 into r130;
|
||||
add r127 r130 into r131;
|
||||
ternary r128 r131 r127 into r132;
|
||||
lt 26u64 r2 into r133;
|
||||
mul r132 r1 into r134;
|
||||
div r134 10000u64 into r135;
|
||||
add r132 r135 into r136;
|
||||
ternary r133 r136 r132 into r137;
|
||||
lt 27u64 r2 into r138;
|
||||
mul r137 r1 into r139;
|
||||
div r139 10000u64 into r140;
|
||||
add r137 r140 into r141;
|
||||
ternary r138 r141 r137 into r142;
|
||||
lt 28u64 r2 into r143;
|
||||
mul r142 r1 into r144;
|
||||
div r144 10000u64 into r145;
|
||||
add r142 r145 into r146;
|
||||
ternary r143 r146 r142 into r147;
|
||||
lt 29u64 r2 into r148;
|
||||
mul r147 r1 into r149;
|
||||
div r149 10000u64 into r150;
|
||||
add r147 r150 into r151;
|
||||
ternary r148 r151 r147 into r152;
|
||||
lt 30u64 r2 into r153;
|
||||
mul r152 r1 into r154;
|
||||
div r154 10000u64 into r155;
|
||||
add r152 r155 into r156;
|
||||
ternary r153 r156 r152 into r157;
|
||||
lt 31u64 r2 into r158;
|
||||
mul r157 r1 into r159;
|
||||
div r159 10000u64 into r160;
|
||||
add r157 r160 into r161;
|
||||
ternary r158 r161 r157 into r162;
|
||||
lt 32u64 r2 into r163;
|
||||
mul r162 r1 into r164;
|
||||
div r164 10000u64 into r165;
|
||||
add r162 r165 into r166;
|
||||
ternary r163 r166 r162 into r167;
|
||||
lt 33u64 r2 into r168;
|
||||
mul r167 r1 into r169;
|
||||
div r169 10000u64 into r170;
|
||||
add r167 r170 into r171;
|
||||
ternary r168 r171 r167 into r172;
|
||||
lt 34u64 r2 into r173;
|
||||
mul r172 r1 into r174;
|
||||
div r174 10000u64 into r175;
|
||||
add r172 r175 into r176;
|
||||
ternary r173 r176 r172 into r177;
|
||||
lt 35u64 r2 into r178;
|
||||
mul r177 r1 into r179;
|
||||
div r179 10000u64 into r180;
|
||||
add r177 r180 into r181;
|
||||
ternary r178 r181 r177 into r182;
|
||||
lt 36u64 r2 into r183;
|
||||
mul r182 r1 into r184;
|
||||
div r184 10000u64 into r185;
|
||||
add r182 r185 into r186;
|
||||
ternary r183 r186 r182 into r187;
|
||||
lt 37u64 r2 into r188;
|
||||
mul r187 r1 into r189;
|
||||
div r189 10000u64 into r190;
|
||||
add r187 r190 into r191;
|
||||
ternary r188 r191 r187 into r192;
|
||||
lt 38u64 r2 into r193;
|
||||
mul r192 r1 into r194;
|
||||
div r194 10000u64 into r195;
|
||||
add r192 r195 into r196;
|
||||
ternary r193 r196 r192 into r197;
|
||||
lt 39u64 r2 into r198;
|
||||
mul r197 r1 into r199;
|
||||
div r199 10000u64 into r200;
|
||||
add r197 r200 into r201;
|
||||
ternary r198 r201 r197 into r202;
|
||||
lt 40u64 r2 into r203;
|
||||
mul r202 r1 into r204;
|
||||
div r204 10000u64 into r205;
|
||||
add r202 r205 into r206;
|
||||
ternary r203 r206 r202 into r207;
|
||||
lt 41u64 r2 into r208;
|
||||
mul r207 r1 into r209;
|
||||
div r209 10000u64 into r210;
|
||||
add r207 r210 into r211;
|
||||
ternary r208 r211 r207 into r212;
|
||||
lt 42u64 r2 into r213;
|
||||
mul r212 r1 into r214;
|
||||
div r214 10000u64 into r215;
|
||||
add r212 r215 into r216;
|
||||
ternary r213 r216 r212 into r217;
|
||||
lt 43u64 r2 into r218;
|
||||
mul r217 r1 into r219;
|
||||
div r219 10000u64 into r220;
|
||||
add r217 r220 into r221;
|
||||
ternary r218 r221 r217 into r222;
|
||||
lt 44u64 r2 into r223;
|
||||
mul r222 r1 into r224;
|
||||
div r224 10000u64 into r225;
|
||||
add r222 r225 into r226;
|
||||
ternary r223 r226 r222 into r227;
|
||||
lt 45u64 r2 into r228;
|
||||
mul r227 r1 into r229;
|
||||
div r229 10000u64 into r230;
|
||||
add r227 r230 into r231;
|
||||
ternary r228 r231 r227 into r232;
|
||||
lt 46u64 r2 into r233;
|
||||
mul r232 r1 into r234;
|
||||
div r234 10000u64 into r235;
|
||||
add r232 r235 into r236;
|
||||
ternary r233 r236 r232 into r237;
|
||||
lt 47u64 r2 into r238;
|
||||
mul r237 r1 into r239;
|
||||
div r239 10000u64 into r240;
|
||||
add r237 r240 into r241;
|
||||
ternary r238 r241 r237 into r242;
|
||||
lt 48u64 r2 into r243;
|
||||
mul r242 r1 into r244;
|
||||
div r244 10000u64 into r245;
|
||||
add r242 r245 into r246;
|
||||
ternary r243 r246 r242 into r247;
|
||||
lt 49u64 r2 into r248;
|
||||
mul r247 r1 into r249;
|
||||
div r249 10000u64 into r250;
|
||||
add r247 r250 into r251;
|
||||
ternary r248 r251 r247 into r252;
|
||||
lt 50u64 r2 into r253;
|
||||
mul r252 r1 into r254;
|
||||
div r254 10000u64 into r255;
|
||||
add r252 r255 into r256;
|
||||
ternary r253 r256 r252 into r257;
|
||||
lt 51u64 r2 into r258;
|
||||
mul r257 r1 into r259;
|
||||
div r259 10000u64 into r260;
|
||||
add r257 r260 into r261;
|
||||
ternary r258 r261 r257 into r262;
|
||||
lt 52u64 r2 into r263;
|
||||
mul r262 r1 into r264;
|
||||
div r264 10000u64 into r265;
|
||||
add r262 r265 into r266;
|
||||
ternary r263 r266 r262 into r267;
|
||||
lt 53u64 r2 into r268;
|
||||
mul r267 r1 into r269;
|
||||
div r269 10000u64 into r270;
|
||||
add r267 r270 into r271;
|
||||
ternary r268 r271 r267 into r272;
|
||||
lt 54u64 r2 into r273;
|
||||
mul r272 r1 into r274;
|
||||
div r274 10000u64 into r275;
|
||||
add r272 r275 into r276;
|
||||
ternary r273 r276 r272 into r277;
|
||||
lt 55u64 r2 into r278;
|
||||
mul r277 r1 into r279;
|
||||
div r279 10000u64 into r280;
|
||||
add r277 r280 into r281;
|
||||
ternary r278 r281 r277 into r282;
|
||||
lt 56u64 r2 into r283;
|
||||
mul r282 r1 into r284;
|
||||
div r284 10000u64 into r285;
|
||||
add r282 r285 into r286;
|
||||
ternary r283 r286 r282 into r287;
|
||||
lt 57u64 r2 into r288;
|
||||
mul r287 r1 into r289;
|
||||
div r289 10000u64 into r290;
|
||||
add r287 r290 into r291;
|
||||
ternary r288 r291 r287 into r292;
|
||||
lt 58u64 r2 into r293;
|
||||
mul r292 r1 into r294;
|
||||
div r294 10000u64 into r295;
|
||||
add r292 r295 into r296;
|
||||
ternary r293 r296 r292 into r297;
|
||||
lt 59u64 r2 into r298;
|
||||
mul r297 r1 into r299;
|
||||
div r299 10000u64 into r300;
|
||||
add r297 r300 into r301;
|
||||
ternary r298 r301 r297 into r302;
|
||||
lt 60u64 r2 into r303;
|
||||
mul r302 r1 into r304;
|
||||
div r304 10000u64 into r305;
|
||||
add r302 r305 into r306;
|
||||
ternary r303 r306 r302 into r307;
|
||||
lt 61u64 r2 into r308;
|
||||
mul r307 r1 into r309;
|
||||
div r309 10000u64 into r310;
|
||||
add r307 r310 into r311;
|
||||
ternary r308 r311 r307 into r312;
|
||||
lt 62u64 r2 into r313;
|
||||
mul r312 r1 into r314;
|
||||
div r314 10000u64 into r315;
|
||||
add r312 r315 into r316;
|
||||
ternary r313 r316 r312 into r317;
|
||||
lt 63u64 r2 into r318;
|
||||
mul r317 r1 into r319;
|
||||
div r319 10000u64 into r320;
|
||||
add r317 r320 into r321;
|
||||
ternary r318 r321 r317 into r322;
|
||||
lt 64u64 r2 into r323;
|
||||
mul r322 r1 into r324;
|
||||
div r324 10000u64 into r325;
|
||||
add r322 r325 into r326;
|
||||
ternary r323 r326 r322 into r327;
|
||||
lt 65u64 r2 into r328;
|
||||
mul r327 r1 into r329;
|
||||
div r329 10000u64 into r330;
|
||||
add r327 r330 into r331;
|
||||
ternary r328 r331 r327 into r332;
|
||||
lt 66u64 r2 into r333;
|
||||
mul r332 r1 into r334;
|
||||
div r334 10000u64 into r335;
|
||||
add r332 r335 into r336;
|
||||
ternary r333 r336 r332 into r337;
|
||||
lt 67u64 r2 into r338;
|
||||
mul r337 r1 into r339;
|
||||
div r339 10000u64 into r340;
|
||||
add r337 r340 into r341;
|
||||
ternary r338 r341 r337 into r342;
|
||||
lt 68u64 r2 into r343;
|
||||
mul r342 r1 into r344;
|
||||
div r344 10000u64 into r345;
|
||||
add r342 r345 into r346;
|
||||
ternary r343 r346 r342 into r347;
|
||||
lt 69u64 r2 into r348;
|
||||
mul r347 r1 into r349;
|
||||
div r349 10000u64 into r350;
|
||||
add r347 r350 into r351;
|
||||
ternary r348 r351 r347 into r352;
|
||||
lt 70u64 r2 into r353;
|
||||
mul r352 r1 into r354;
|
||||
div r354 10000u64 into r355;
|
||||
add r352 r355 into r356;
|
||||
ternary r353 r356 r352 into r357;
|
||||
lt 71u64 r2 into r358;
|
||||
mul r357 r1 into r359;
|
||||
div r359 10000u64 into r360;
|
||||
add r357 r360 into r361;
|
||||
ternary r358 r361 r357 into r362;
|
||||
lt 72u64 r2 into r363;
|
||||
mul r362 r1 into r364;
|
||||
div r364 10000u64 into r365;
|
||||
add r362 r365 into r366;
|
||||
ternary r363 r366 r362 into r367;
|
||||
lt 73u64 r2 into r368;
|
||||
mul r367 r1 into r369;
|
||||
div r369 10000u64 into r370;
|
||||
add r367 r370 into r371;
|
||||
ternary r368 r371 r367 into r372;
|
||||
lt 74u64 r2 into r373;
|
||||
mul r372 r1 into r374;
|
||||
div r374 10000u64 into r375;
|
||||
add r372 r375 into r376;
|
||||
ternary r373 r376 r372 into r377;
|
||||
lt 75u64 r2 into r378;
|
||||
mul r377 r1 into r379;
|
||||
div r379 10000u64 into r380;
|
||||
add r377 r380 into r381;
|
||||
ternary r378 r381 r377 into r382;
|
||||
lt 76u64 r2 into r383;
|
||||
mul r382 r1 into r384;
|
||||
div r384 10000u64 into r385;
|
||||
add r382 r385 into r386;
|
||||
ternary r383 r386 r382 into r387;
|
||||
lt 77u64 r2 into r388;
|
||||
mul r387 r1 into r389;
|
||||
div r389 10000u64 into r390;
|
||||
add r387 r390 into r391;
|
||||
ternary r388 r391 r387 into r392;
|
||||
lt 78u64 r2 into r393;
|
||||
mul r392 r1 into r394;
|
||||
div r394 10000u64 into r395;
|
||||
add r392 r395 into r396;
|
||||
ternary r393 r396 r392 into r397;
|
||||
lt 79u64 r2 into r398;
|
||||
mul r397 r1 into r399;
|
||||
div r399 10000u64 into r400;
|
||||
add r397 r400 into r401;
|
||||
ternary r398 r401 r397 into r402;
|
||||
lt 80u64 r2 into r403;
|
||||
mul r402 r1 into r404;
|
||||
div r404 10000u64 into r405;
|
||||
add r402 r405 into r406;
|
||||
ternary r403 r406 r402 into r407;
|
||||
lt 81u64 r2 into r408;
|
||||
mul r407 r1 into r409;
|
||||
div r409 10000u64 into r410;
|
||||
add r407 r410 into r411;
|
||||
ternary r408 r411 r407 into r412;
|
||||
lt 82u64 r2 into r413;
|
||||
mul r412 r1 into r414;
|
||||
div r414 10000u64 into r415;
|
||||
add r412 r415 into r416;
|
||||
ternary r413 r416 r412 into r417;
|
||||
lt 83u64 r2 into r418;
|
||||
mul r417 r1 into r419;
|
||||
div r419 10000u64 into r420;
|
||||
add r417 r420 into r421;
|
||||
ternary r418 r421 r417 into r422;
|
||||
lt 84u64 r2 into r423;
|
||||
mul r422 r1 into r424;
|
||||
div r424 10000u64 into r425;
|
||||
add r422 r425 into r426;
|
||||
ternary r423 r426 r422 into r427;
|
||||
lt 85u64 r2 into r428;
|
||||
mul r427 r1 into r429;
|
||||
div r429 10000u64 into r430;
|
||||
add r427 r430 into r431;
|
||||
ternary r428 r431 r427 into r432;
|
||||
lt 86u64 r2 into r433;
|
||||
mul r432 r1 into r434;
|
||||
div r434 10000u64 into r435;
|
||||
add r432 r435 into r436;
|
||||
ternary r433 r436 r432 into r437;
|
||||
lt 87u64 r2 into r438;
|
||||
mul r437 r1 into r439;
|
||||
div r439 10000u64 into r440;
|
||||
add r437 r440 into r441;
|
||||
ternary r438 r441 r437 into r442;
|
||||
lt 88u64 r2 into r443;
|
||||
mul r442 r1 into r444;
|
||||
div r444 10000u64 into r445;
|
||||
add r442 r445 into r446;
|
||||
ternary r443 r446 r442 into r447;
|
||||
lt 89u64 r2 into r448;
|
||||
mul r447 r1 into r449;
|
||||
div r449 10000u64 into r450;
|
||||
add r447 r450 into r451;
|
||||
ternary r448 r451 r447 into r452;
|
||||
lt 90u64 r2 into r453;
|
||||
mul r452 r1 into r454;
|
||||
div r454 10000u64 into r455;
|
||||
add r452 r455 into r456;
|
||||
ternary r453 r456 r452 into r457;
|
||||
lt 91u64 r2 into r458;
|
||||
mul r457 r1 into r459;
|
||||
div r459 10000u64 into r460;
|
||||
add r457 r460 into r461;
|
||||
ternary r458 r461 r457 into r462;
|
||||
lt 92u64 r2 into r463;
|
||||
mul r462 r1 into r464;
|
||||
div r464 10000u64 into r465;
|
||||
add r462 r465 into r466;
|
||||
ternary r463 r466 r462 into r467;
|
||||
lt 93u64 r2 into r468;
|
||||
mul r467 r1 into r469;
|
||||
div r469 10000u64 into r470;
|
||||
add r467 r470 into r471;
|
||||
ternary r468 r471 r467 into r472;
|
||||
lt 94u64 r2 into r473;
|
||||
mul r472 r1 into r474;
|
||||
div r474 10000u64 into r475;
|
||||
add r472 r475 into r476;
|
||||
ternary r473 r476 r472 into r477;
|
||||
lt 95u64 r2 into r478;
|
||||
mul r477 r1 into r479;
|
||||
div r479 10000u64 into r480;
|
||||
add r477 r480 into r481;
|
||||
ternary r478 r481 r477 into r482;
|
||||
lt 96u64 r2 into r483;
|
||||
mul r482 r1 into r484;
|
||||
div r484 10000u64 into r485;
|
||||
add r482 r485 into r486;
|
||||
ternary r483 r486 r482 into r487;
|
||||
lt 97u64 r2 into r488;
|
||||
mul r487 r1 into r489;
|
||||
div r489 10000u64 into r490;
|
||||
add r487 r490 into r491;
|
||||
ternary r488 r491 r487 into r492;
|
||||
lt 98u64 r2 into r493;
|
||||
mul r492 r1 into r494;
|
||||
div r494 10000u64 into r495;
|
||||
add r492 r495 into r496;
|
||||
ternary r493 r496 r492 into r497;
|
||||
lt 99u64 r2 into r498;
|
||||
mul r497 r1 into r499;
|
||||
div r499 10000u64 into r500;
|
||||
add r497 r500 into r501;
|
||||
ternary r498 r501 r497 into r502;
|
||||
output r502 as u64;
|
||||
|
||||
|
||||
|
||||
function withdraw:
|
||||
input r0 as address.private;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
input r3 as u64.private;
|
||||
assert.eq self.caller aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px;
|
||||
hash.bhp256 r0 into r4 as field;
|
||||
call calculate_interest r1 r2 r3 into r5;
|
||||
cast r0 r5 into r6 as Token.record;
|
||||
async withdraw r4 r1 into r7;
|
||||
output r6 as Token.record;
|
||||
output r7 as basic_bank.aleo/withdraw.future;
|
||||
|
||||
finalize withdraw:
|
||||
input r0 as field.public;
|
||||
input r1 as u64.public;
|
||||
get.or_use balances[r0] 0u64 into r2;
|
||||
sub r2 r1 into r3;
|
||||
set r3 into balances[r0];
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "basic_bank.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "basic_bank.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
#!/bin/bash
|
||||
# First check that Leo is installed.
|
||||
if ! command -v leo &> /dev/null
|
||||
then
|
||||
echo "leo is not installed."
|
||||
exit
|
||||
fi
|
||||
|
||||
# The private key and address of the bank.
|
||||
# Swap these into program.json, when running transactions as the bank.
|
||||
# NETWORK=testnet
|
||||
# PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
|
||||
# The private key and address of the user.
|
||||
# Swap these into program.json, when running transactions as the user.
|
||||
# NETWORK=testnet
|
||||
# PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
|
||||
# Swap in the private key and address of the bank to .env.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
# Have the bank issue 100 tokens to the user.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 1: Initialize 100 tokens for aleo1s3ws5...em2u4t ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | ACTION | AMOUNT | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Issuing | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Depositing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Withdrawing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | WALLET | aleo1s3ws5...em2u4t | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | BANK | aleo1rhgdu...vzp9px | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Periods | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Interest Rate | 12.34% | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | TOTAL BALANCE | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run issue aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t 100u64 || exit
|
||||
|
||||
|
||||
# Swap in the private key and address of the user to .env.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
# Have the user deposit 50 tokens into the bank.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 2: aleo1s3ws5...em2u4t deposits 50 tokens ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | ACTION | AMOUNT | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Issuing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Depositing | 50 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Withdrawing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | WALLET | aleo1s3ws5...em2u4t | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 50 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | BANK | aleo1rhgdu...vzp9px | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 50 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Periods | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Interest Rate | 12.34% | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | TOTAL BALANCE | 100 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run deposit "{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
amount: 100u64.private,
|
||||
_nonce: 4668394794828730542675887906815309351994017139223602571716627453741502624516group.public
|
||||
}" 50u64 || exit
|
||||
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 3: Wait 15 periods ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | ACTION | AMOUNT | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Issuing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Depositing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Withdrawing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | WALLET | aleo1s3ws5...em2u4t | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 50 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | BANK | aleo1rhgdu...vzp9px | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 266 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Periods | 15 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Interest Rate | 12.34% | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | TOTAL BALANCE | 316 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
# Swap in the private key and address of the bank to .env.
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
# Have the bank withdraw all of the user's tokens with compound interest over 15 periods at 12.34%.
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 4: Withdraw tokens of aleo1s3ws5...em2u4t w/ interest ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | ACTION | AMOUNT | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Issuing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Depositing | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Withdrawing | 266 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | WALLET | aleo1s3ws5...em2u4t | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 316 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | BANK | aleo1rhgdu...vzp9px | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Balance | 0 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Periods | 15 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | Interest Rate | 12.34% | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
######## ----------------------------------------- ########
|
||||
######## | TOTAL BALANCE | 316 | ########
|
||||
######## ----------------------------------------- ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run withdraw aleo1t0uer3jgtsgmx5tq6x6f9ecu8tr57rzzfnc2dgmcqldceal0ls9qf6st7a 50u64 1234u64 15u64 || exit
|
||||
|
@ -1,96 +0,0 @@
|
||||
program basic_bank.aleo {
|
||||
// A token, issued by a bank.
|
||||
// - 'owner' : The address of the account that owns the record associated with this token.
|
||||
// - 'amount' : The amount of tokens owned by the account.
|
||||
record Token {
|
||||
owner: address,
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
// An on-chain mapping, storing the amount of tokens owned by each account
|
||||
// The account is stored as a hash to preserve user privacy.
|
||||
mapping balances: field => u64;
|
||||
|
||||
// Returns a new Token.
|
||||
// - `owner` : The address of the account to issue the token to.
|
||||
// - `amount`: The amount of tokens to issue.
|
||||
// Requires that the function caller is the bank.
|
||||
// The bank's address is aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.
|
||||
transition issue(owner: address, amount: u64) -> Token {
|
||||
assert_eq(self.caller, aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px);
|
||||
return Token {
|
||||
owner: owner,
|
||||
amount: amount,
|
||||
};
|
||||
}
|
||||
|
||||
// Deposits some amount of money into the bank.
|
||||
// Returns a new Token with the remaining amount of money.
|
||||
// - `token` : A record containing tokens to deposit.
|
||||
// - `amount`: The amount of tokens to deposit.
|
||||
async transition deposit(token: Token, amount: u64) -> (Token, Future) {
|
||||
let difference: u64 = token.amount - amount;
|
||||
|
||||
let remaining: Token = Token {
|
||||
owner: token.owner,
|
||||
amount: difference,
|
||||
};
|
||||
|
||||
// Compute the hash of the token owner.
|
||||
let hash: field = BHP256::hash_to_field(token.owner);
|
||||
|
||||
return (remaining, finalize_deposit(hash, amount));
|
||||
}
|
||||
|
||||
// Updates on-chain state by the amount of tokens deposited.
|
||||
// - `hash` : The hash of the token owner.
|
||||
// - `amount`: The amount of tokens that were deposited.
|
||||
async function finalize_deposit(hash: field, amount: u64) {
|
||||
let current_amount: u64 = Mapping::get_or_use(balances, hash, 0u64);
|
||||
Mapping::set(balances, hash, current_amount + amount);
|
||||
}
|
||||
|
||||
// Returns a new Token containing the amount of money withdrawn.
|
||||
// - `recipient`: The address of the account to withdraw the tokens to.
|
||||
// - `amount` : The amount of tokens to withdraw.
|
||||
// - `rate` : The compound interest rate.
|
||||
// - `periods` : The number of periods to compound the interest over.
|
||||
// Requires that the function caller is the bank.
|
||||
async transition withdraw(recipient: address, amount: u64, rate: u64, periods: u64) -> (Token, Future) {
|
||||
assert_eq(self.caller, aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px);
|
||||
let hash: field = BHP256::hash_to_field(recipient);
|
||||
|
||||
let total: u64 = calculate_interest(amount, rate, periods);
|
||||
|
||||
let token: Token = Token {
|
||||
owner: recipient,
|
||||
amount: total,
|
||||
};
|
||||
|
||||
return (token, finalize_withdraw(hash, amount));
|
||||
}
|
||||
|
||||
// Updates on-chain state by the amount of tokens withdrawn.
|
||||
// - `hash` : The hash of the token owner.
|
||||
// - `amount`: The amount of tokens that were withdrawn.
|
||||
async function finalize_withdraw(hash: field, amount: u64) {
|
||||
let current_amount: u64 = Mapping::get_or_use(balances, hash, 0u64);
|
||||
Mapping::set(balances, hash, current_amount - amount);
|
||||
}
|
||||
|
||||
// Returns the total amount of tokens after compounding interest.
|
||||
// - `principal`: The amount of tokens to compound interest over.
|
||||
// - `rate` : The compound interest rate.
|
||||
// - `periods` : The number of periods to compound the interest over.
|
||||
function calculate_interest(principal: u64, rate: u64, periods: u64) -> u64 {
|
||||
let amount: u64 = principal;
|
||||
|
||||
for i:u64 in 0u64..100u64 {
|
||||
if i < periods {
|
||||
amount += (amount * rate) / 10000u64;
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
ENDPOINT=http://localhost:3030
|
||||
|
4
examples/battleship/.gitignore
vendored
4
examples/battleship/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,910 +0,0 @@
|
||||
<!-- # Leo Battleship 🏴☠️ -->
|
||||
|
||||
[//]: # (<img alt="workshop/battleship" width="1412" src="../.resources/battleship.png">)
|
||||
|
||||
- [Summary](#summary)
|
||||
- [Build](#how-to-build)
|
||||
- [Run](#how-to-run)
|
||||
- [1. Initializing the Players](#1-initializing-the-players)
|
||||
- [2: Player 1 Places Ships On The Board](#2-player-1-places-ships-on-the-board)
|
||||
- [3: Player 1 Passes The Board To Player 2](#3-player-1-passes-the-board-to-player-2)
|
||||
- [4: Player 2 Places Ships On The Board](#4-player-2-places-ships-on-the-board)
|
||||
- [5: Passing The Board Back To Player 1](#5-passing-the-board-back-to-player-1)
|
||||
- [6: Player 1 Takes The 1st Turn](#6-player-1-takes-the-1st-turn)
|
||||
- [7: Player 2 Takes The 2nd Turn](#7-player-2-takes-the-2nd-turn)
|
||||
- [8: Player 1 Takes The 3rd Turn](#8-player-1-takes-the-3rd-turn)
|
||||
- [9: Player 2 Takes The 4th Turn](#9-player-2-takes-the-4th-turn)
|
||||
- [10. Who Wins?](#10-who-wins)
|
||||
- [Graphical Representation](#graphical-representation)
|
||||
- [ZK Battleship Privacy](#zk-battleship-privacy)
|
||||
- [Modeling the Boards and Ships](#modeling-the-board-and-ships)
|
||||
- [Validating a Single Ship](#validating-a-single-ship-at-a-time)
|
||||
- [Validating all Ships](#validating-all-ships-together-in-a-single-board)
|
||||
- [Sequencing Game State](#ensure-that-players-and-boards-cannot-swap-mid-game)
|
||||
- [Preventing Double Moves](#ensure-that-each-player-can-only-move-once-before-the-next-player-can-move)
|
||||
- [Ensuring Valid Moves](#enforce-constraints-on-valid-moves-and-force-the-player-to-give-their-opponent-information-about-their-opponents-previous-move-in-order-to-continue-playing)
|
||||
- [Winning](#winning-the-game)
|
||||
|
||||
# Summary
|
||||
Battleship is a game where two players lay their ships into secret configurations on their respective 8x8 grids,
|
||||
and then take turns firing upon each other's board.
|
||||
The game ends when one player has sunk all of the other player's ships.
|
||||
|
||||
This application was translated into Leo from the [zk-battleship](https://github.com/demox-labs/zk-battleship) example written by the Aleo community - show them some love!
|
||||
|
||||
## How to Build
|
||||
|
||||
To compile this Leo program, run:
|
||||
```bash
|
||||
leo run <function_name> <function_inputs>
|
||||
```
|
||||
|
||||
## How to Run
|
||||
<details open><summary>Commands and Playing the Game</summary>
|
||||
|
||||
### 1. Initializing the Players
|
||||
In order to play battleship, there must be two players with two boards.
|
||||
Players will be represented by their Aleo address.
|
||||
You can use the provided player accounts or [generate your own](https://aleohq.github.io/aleo/).
|
||||
```markdown
|
||||
Player 1:
|
||||
Private Key APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
View Key AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6
|
||||
Address aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px
|
||||
|
||||
Player 2:
|
||||
Private Key APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
View Key AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE
|
||||
Address aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t
|
||||
```
|
||||
|
||||
Save the keys and addresses. Set the `program.json` private key and address to one of the newly created aleo accounts. We'll refer to this address as Player 1, and the other address as Player 2.
|
||||
|
||||
```json
|
||||
{
|
||||
"program": "battleship.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "Play ZK Battleship",
|
||||
"development": {
|
||||
"private_key": "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH",
|
||||
"view_key": "AViewKey1fSyEPXxfPFVgjL6qcM9izWRGrhSHKXyN3c64BNsAjnA6",
|
||||
"address": "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Player 1 Places Ships on the Board
|
||||
Now, we need to make a board as Player 1.
|
||||
See the [modeling the boards and ships](#modeling-the-board-and-ships) section for information on valid ship bitstrings and placements on the board.
|
||||
For this example, we will be using sample valid inputs.
|
||||
Initialize a new board as Player 1 with valid ship inputs and Player 2's address: `leo run initialize_board ship_5_bitstring ship_4_bitstring ship_3_bitstring ship_2_bitstring player_2_address`
|
||||
|
||||
**Run**
|
||||
```
|
||||
leo run initialize_board 34084860461056u64 551911718912u64 7u64 1157425104234217472u64 aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t
|
||||
```
|
||||
**Output**
|
||||
```bash
|
||||
➡️ Output
|
||||
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: false.private,
|
||||
_nonce: 3887646704618532506963887075433683846689834495661101507703164090915348189037group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/initialize_board'
|
||||
```
|
||||
|
||||
The output is a `board_state` record owned by Player 1.
|
||||
Notice that the `game_started` flag is false, and that the composite ship configuration `ships`
|
||||
1157459741006397447u64, as a binary bitstring, is `0001000000010000000111111000000010000000100000001000000000000111`,
|
||||
which laid out in columns and rows is:
|
||||
```
|
||||
0 0 0 1 0 0 0 0
|
||||
0 0 0 1 0 0 0 0
|
||||
0 0 0 1 1 1 1 1
|
||||
1 0 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 1 1 1
|
||||
```
|
||||
|
||||
### 3: Player 1 Passes The Board To Player 2
|
||||
Now, we can offer a battleship game to player 2. Run `leo run offer_battleship 'board_state.record'` with the record you just created:
|
||||
**Run**
|
||||
```
|
||||
leo run offer_battleship '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: false.private,
|
||||
_nonce: 3887646704618532506963887075433683846689834495661101507703164090915348189037group.public
|
||||
}'
|
||||
```
|
||||
|
||||
**Output**
|
||||
```bash
|
||||
➡️ Outputs
|
||||
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 6563064852163330630334088854834332804417910882908622526775624018226782316843group.public
|
||||
}
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 0u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 4374626042494973146987320062571809401151262172766172816829659487584978644457group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/offer_battleship'
|
||||
```
|
||||
|
||||
The first output record is the updated `board_state` record.
|
||||
Notice the `game_started` flag is now true.
|
||||
This board cannot be used to offer any other battleship games or accept any battleship game offers.
|
||||
Player 1 would need to initialize a new board and use that instead.
|
||||
The second output record is a dummy `move` record --
|
||||
there are no fire coordinates included to play on Player 2's board,
|
||||
and no information about any previous Player 2 moves (Player 2 has not made any moves yet).
|
||||
This `move` record is owned by Player 2, who must use that in combination with their own `board_state` record to accept the game. Let's do that now.
|
||||
|
||||
### 4: Player 2 Places Ships On The Board
|
||||
We must run the program as Player 2 now, so switch the `program.json` file to use Player 2's keys:
|
||||
```json
|
||||
{
|
||||
"program": "battleship.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "Play ZK Battleship",
|
||||
"development": {
|
||||
"private_key": "APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh",
|
||||
"view_key": "AViewKey1hh6dvSEgeMdfseP4hfdbNYjX4grETwCuTbKnCftkpMwE",
|
||||
"address": "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
```
|
||||
|
||||
We'll create a new and different board for Player 2, and make sure to include Player 1's address as the opponent:
|
||||
**Run**
|
||||
```bash
|
||||
leo run initialize_board 31u64 2207646875648u64 224u64 9042383626829824u64 aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px
|
||||
```
|
||||
|
||||
**Output**
|
||||
```bash
|
||||
➡️ Output
|
||||
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: false.private,
|
||||
_nonce: 1549419609469324182591325047490602235361156298832591378925133482196483208807group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/initialize_board'
|
||||
```
|
||||
|
||||
Note, the output ships here is 9044591273705727u64, which in a bitstring is:
|
||||
```
|
||||
0 0 1 0 0 0 0 0
|
||||
0 0 1 0 0 0 1 0
|
||||
0 0 0 0 0 0 1 0
|
||||
0 0 0 0 0 0 1 0
|
||||
0 0 0 0 0 0 1 0
|
||||
0 0 0 0 0 0 0 0
|
||||
1 1 1 1 1 1 1 1
|
||||
```
|
||||
|
||||
### 5: Passing The Board Back To Player 1
|
||||
Now, we can accept Player 1's offer. Run `leo run start_battleship 'board_state.record' 'move.record'`:
|
||||
**Run**
|
||||
```bash
|
||||
leo run start_battleship '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: false.private,
|
||||
_nonce: 1549419609469324182591325047490602235361156298832591378925133482196483208807group.public
|
||||
}' '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 0u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 4374626042494973146987320062571809401151262172766172816829659487584978644457group.public
|
||||
}'
|
||||
```
|
||||
|
||||
**Outputs**
|
||||
```bash
|
||||
➡️ Outputs
|
||||
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: true.private,
|
||||
_nonce: 6222383571142756260765569201308836492199048237638652378826141459336360362251group.public
|
||||
}
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 0u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 3742551407126138397717446975757978589064777004441277005584760115236217735495group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/start_battleship'
|
||||
```
|
||||
|
||||
Notice the outputs here are similar to `offer_battleship`.
|
||||
A dummy `move` record is owned by Player 1, and Player 2 gets a `board_state` record with the `game_started` flag updated.
|
||||
However, now that Player 1 has a `move` record and a started board, they can begin to play.
|
||||
|
||||
### 6: Player 1 Takes The 1st Turn
|
||||
**Switch** `program.json`'s keys back to Player 1's.
|
||||
Player 1 now makes the first real move: `leo run play 'board_state.record' 'move.record' fire_coordinate`
|
||||
|
||||
**Run**
|
||||
```bash
|
||||
leo run play '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 6563064852163330630334088854834332804417910882908622526775624018226782316843group.public
|
||||
}' '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 0u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 3742551407126138397717446975757978589064777004441277005584760115236217735495group.public
|
||||
}' 1u64
|
||||
```
|
||||
**Outputs**
|
||||
```bash
|
||||
➡️ Outputs
|
||||
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 1u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 1474170213684980843727833284550698461565286563122422722760769547002894080093group.public
|
||||
}
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 1u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 5481529266389297320813092061136936339861329677911328036818179854958874588416group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/play'
|
||||
```
|
||||
|
||||
Player 1 has an updated `board_state` record -- they have a new `played_tiles` bitstring,
|
||||
which corresponds to the fire coordinate they just sent to Player 2.
|
||||
You can see that the `incoming_fire_coordinate` in the `move` record owned by Player 2 matches exactly the input given by Player 1.
|
||||
Player 2 can now play this move tile and respond with a fire coordinate of their own,
|
||||
and they will also let Player 1 know whether their fire coordinate hit or miss Player 2's ships.
|
||||
|
||||
### 7: Player 2 Takes The 2nd Turn
|
||||
**Switch** `program.json` to Player 2's keys. Player 2 makes their move:
|
||||
|
||||
**Run**
|
||||
```bash
|
||||
leo run play '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: true.private,
|
||||
_nonce: 6222383571142756260765569201308836492199048237638652378826141459336360362251group.public
|
||||
}' '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 1u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 5481529266389297320813092061136936339861329677911328036818179854958874588416group.public
|
||||
}' 2048u64
|
||||
|
||||
```
|
||||
|
||||
**Outputs**
|
||||
```bash
|
||||
➡️ Outputs
|
||||
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 2048u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: true.private,
|
||||
_nonce: 5254963165391133332409074172682159033621708071536429341861038147524454777097group.public
|
||||
}
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 2048u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 1u64.private,
|
||||
_nonce: 5851606198769770675504009323414373017067582072428989801313256693053765675198group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/play'
|
||||
```
|
||||
|
||||
Player 2 now has an updated `board_state` record which includes their newly updated `played_tiles`,
|
||||
only containing the fire coordinate they just sent to Player 1.
|
||||
Player 1 now owns a new `move` record which includes the `prev_hits_and_misses` component.
|
||||
This contains only the result of Player 1's previous fire coordinate they had sent to Player 2.
|
||||
It will always be a single coordinate on the 8x8 grid if it's a hit. A miss is 0u64 (8x8 grid of 0s),
|
||||
whereas a hit is the u64 equivalent of their previous fire coordinate in bitstring form.
|
||||
If you check Player 2's ships configuration, you'll note their entire bottom row is covered by two ships,
|
||||
so sample valid hits on the bottom row would be: 1u64, 2u64, 4u64, 8u64, 16u64, 32u64, 64u64, and 128u64.
|
||||
Since Player 1's first fire coordinate (1u64) was a hit, the `prev_hits_and_misses` component is also 1u64.
|
||||
|
||||
Player 1's next move will consume this `move` record, which will update Player 1's board with the hit-or-miss,
|
||||
as well as figure out the result of Player 2's fire coordinate.
|
||||
Now that Player 1 has some `played_tiles`, they can no longer choose an already-played fire coordinate.
|
||||
For example, running `aleo run play 'board_state.record' 'move.record' 1u64` will fail, because 1u64 has already been played.
|
||||
|
||||
### 8: Player 1 Takes The 3rd Turn
|
||||
**Switch** `program.json` to use Player 1's keys.
|
||||
|
||||
**Run**
|
||||
```bash
|
||||
leo run play '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 1u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 1474170213684980843727833284550698461565286563122422722760769547002894080093group.public
|
||||
}' '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 2048u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 1u64.private,
|
||||
_nonce: 5851606198769770675504009323414373017067582072428989801313256693053765675198group.public
|
||||
}' 2u64
|
||||
```
|
||||
|
||||
**Outputs**
|
||||
```bash
|
||||
➡️ Outputs
|
||||
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 1u64.private,
|
||||
played_tiles: 3u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 853278652528988609827041334083853520436225751739504321439524466875699631772group.public
|
||||
}
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 2u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 710336412388939616658264778971886770861024495941253598683184288448156545822group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/play'
|
||||
```
|
||||
|
||||
As before, both a `board_state` record and `move` record are created.
|
||||
The `board_state` record now contains 3u64 as the `played_tiles`, which looks like this in bitstring form:
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 1 1
|
||||
```
|
||||
|
||||
The `board_state` record `hits_and_misses` component has also been updated with the result of their previous move. The new `move` record owned by Player 2 now contains information about whether Player 2's previous move was a hit or miss, as well as Player 1's new fire coordinate.
|
||||
|
||||
### 9: Player 2 Takes The 4th Turn
|
||||
**Switch** `program.json`'s keys to Player 2. Player 2 makes their next move:
|
||||
|
||||
**Run**
|
||||
```bash
|
||||
leo run play '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 2048u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: true.private,
|
||||
_nonce: 5254963165391133332409074172682159033621708071536429341861038147524454777097group.public
|
||||
}' '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 2u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 710336412388939616658264778971886770861024495941253598683184288448156545822group.public
|
||||
}' 4u64
|
||||
```
|
||||
|
||||
**Outputs**
|
||||
```bash
|
||||
➡️ Outputs
|
||||
|
||||
• {
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 2052u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
game_started: true.private,
|
||||
_nonce: 1145182747531998766752104305052328886102707397061849372000385383229513301534group.public
|
||||
}
|
||||
• {
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 4u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 2u64.private,
|
||||
_nonce: 5958326936461495382488152485080596366937963499216527548334225566230682598418group.public
|
||||
}
|
||||
|
||||
✅ Executed 'battleship.aleo/play'
|
||||
```
|
||||
|
||||
### 10. Who Wins?
|
||||
Play continues back and forth between Player 1 and Player 2.
|
||||
When one player has a total of 14 flipped bits in their `hits_and_misses` component on their `board_state` record,
|
||||
they have won the game.
|
||||
|
||||
### Graphical Representation
|
||||
|
||||
The following diagram depicts the records and transitions in a game.
|
||||
|
||||
![diagram](./diagram.png)
|
||||
|
||||
</details>
|
||||
|
||||
## ZK Battleship Privacy
|
||||
|
||||
How can we ensure that the ship configurations of each player remains secret,
|
||||
while being able to trustlessly and fairly play with their opponent?
|
||||
By taking advantage of selective privacy powered by zero-knowledge proofs on Aleo.
|
||||
|
||||
Broadly speaking, we can follow this general strategy:
|
||||
|
||||
1. Create mathematical rules for placing the ships on the board, to ensure that neither player can cheat by stacking all their ships in one place, moving them off the board, or laying them across each other.
|
||||
|
||||
2. Ensure that the players and boards that begin a game cannot be swapped out.
|
||||
|
||||
3. Ensure that each player can only move once before the next player can move.
|
||||
|
||||
4. Enforce constraints on valid moves, and force the player to give their opponent information about their opponent's previous move in order to continue playing.
|
||||
|
||||
## Modeling the board and ships
|
||||
|
||||
Most battleship representations in programs use a 64-character string or an array of arrays (8 arrays of 8 elements each) to model the board state. Unfortunately, Leo doesn't represent strings well yet. Luckily for us, Leo has the unsigned 64-bit integer type, `u64`. To represent every space on a battleship board, from top left to bottom right, we can use each bit in a `u64`. For example, an empty board would be:
|
||||
0u64 =
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
Battleship is played with 4 different ship types -- a ship of length 5, length 4, length 3, and length 2. Some versions of battleship have an extra length 3 ship or another extra ship type; however, we will stick to the most basic version for this project. In order to be a valid ship placement, a ship must be placed vertically or horizontally (not diagonally). On a physical board, a ship cannot break across rows or intersect with another ship, but ships are allowed to touch one another.
|
||||
|
||||
Similar to how we represent a board with a `u64` bitstring, we can represent a ship horizontally as a bitstring. We "flip" the bits to represent a ship:
|
||||
| Length | Bitstring | u64 |
|
||||
| ------ | --------- | --- |
|
||||
| 5 | 11111 | 31u64|
|
||||
| 4 | 1111 | 15u64|
|
||||
| 3 | 111 | 7u64 |
|
||||
| 2 | 11 | 3u64 |
|
||||
|
||||
We can also represent a ship vertically as a bitstring. To show this, we need 7 "unflipped" bits (zeroes) in between the flipped bits so that the bits are adjacent vertically.
|
||||
| Length | Bitstring | u64 |
|
||||
| --- | --- | --- |
|
||||
| 5 | 1 00000001 00000001 00000001 00000001 | 4311810305u64 |
|
||||
| 4 | 1 00000001 00000001 00000001 | 16843009u64 |
|
||||
| 3 | 1 00000001 00000001 | 65793u64 |
|
||||
| 2 | 1 00000001 | 257u64 |
|
||||
|
||||
With a board model and ship bitstring models, we can now place ships on a board.
|
||||
|
||||
<details><summary>Examples of valid board configurations:</summary>
|
||||
|
||||
17870284429256033024u64
|
||||
```
|
||||
1 1 1 1 1 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
1 1 1 1 0 0 0 1
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 1 1
|
||||
0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
16383u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1
|
||||
```
|
||||
|
||||
2157505700798988545u64
|
||||
```
|
||||
0 0 0 1 1 1 0 1
|
||||
1 1 1 1 0 0 0 1
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Examples of invalid board configurations:</summary>
|
||||
|
||||
Ships overlapping the bottom ship:
|
||||
67503903u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 1 0 0
|
||||
0 0 0 0 0 1 1 0
|
||||
0 0 0 0 0 1 1 1
|
||||
0 0 0 1 1 1 1 1
|
||||
```
|
||||
|
||||
Diagonal ships:
|
||||
9242549787790754436u64
|
||||
```
|
||||
1 0 0 0 0 0 0 0
|
||||
0 1 0 0 0 1 0 0
|
||||
0 0 1 0 0 0 1 0
|
||||
0 0 0 1 0 0 0 0
|
||||
0 0 0 1 1 0 0 0
|
||||
0 0 1 0 0 0 0 1
|
||||
0 1 0 0 0 0 1 0
|
||||
1 0 0 0 0 1 0 0
|
||||
```
|
||||
|
||||
Ships splitting across rows and columns:
|
||||
1297811850814034450u64
|
||||
```
|
||||
0 0 0 1 0 0 1 0
|
||||
0 0 0 0 0 0 1 0
|
||||
1 1 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 0
|
||||
1 0 0 1 0 0 0 1
|
||||
0 0 0 1 0 0 0 0
|
||||
0 0 0 1 0 0 1 0
|
||||
0 0 0 1 0 0 1 0
|
||||
```
|
||||
</details>
|
||||
|
||||
Given these rules, our strategy will be to validate each individual ship bitstring placement on a board, and then, if all the ships are valid, compose all the positions onto a board and validate that the board with all ships are valid. If each individual ship's position is valid, then all the ships together should be valid unless any overlapping occurs.
|
||||
|
||||
## Validating a single ship at a time
|
||||
|
||||
To follow along with the code, all verification of ship bitstrings is done in `verify.leo`. We know a ship is valid if all these conditions are met:
|
||||
If horizontal:
|
||||
1. The correct number of bits is flipped (a ship of length 5 should not have 6 flipped bits)
|
||||
2. All the bits are adjacent to each other.
|
||||
3. The bits do not split a row.
|
||||
|
||||
If vertical:
|
||||
1. The correct number of bits is flipped.
|
||||
2. All the bits are adjacent to each other, vertically. This means that each flipped bit should be separated by exactly 7 unflipped bits.
|
||||
3. The bits do not split a column.
|
||||
|
||||
If a ship is valid vertically or horizontally, then we know the ship is valid. We just need to check the bit count, check the adjacency of those bits, and make sure those bits do not split a row/column. However, we can't loop through the bit string to count bits, or to make sure those bits don't break across columns. We'll need to turn to special bitwise operations and hacks.
|
||||
|
||||
<details><summary>Bit Counting</summary>
|
||||
|
||||
See the `bitcount` function to follow along with the code. 50 years ago, MIT AI Laboratory published HAKMEM, which was a series of tricks and hacks to speed up processing for bitwise operations. https://w3.pppl.gov/~hammett/work/2009/AIM-239-ocr.pdf We turned to HAKMEM 169 for bit counting inspiration, although we've tweaked our implementation to be (hopefully) easier to understand. Before diving into details, let's build some intuition.
|
||||
|
||||
Let a,b,c,d be either 0 or 1. Given a polynomial 8a + 4b + 2c + d, how do we find the summation of a + b + c + d?
|
||||
If we subtract subsets of this polynomial, we'll be left with the summation.
|
||||
Step 1: 8a + 4b + 2c + d
|
||||
Step 2: -4a - 2b - c
|
||||
Step 3: -2a - b
|
||||
Step 4: - a
|
||||
Step 5: = a + b + c + d
|
||||
This polynomial is basically a bitwise representation of a number, so given a 4 bit number, e.g. 1011 or 13u64, we can follow these instructions to get the bit count. Step 2 is just subtracting the starting number but shifted to the right once (equivalent to dividing by 2). Step 3 shifts the starting number to the right twice and is subtracted, and Step 4 shifts thrice and is subtracted. Put another way: Start with a 4-digit binary number A, and do `A - (A >> 1) - (A >> 2) - (A >> 3) = B`.
|
||||
Step 1: 1101 = 13u64
|
||||
Step 2: -0110 = 6u64
|
||||
Step 3: -0011 = 3u64
|
||||
Step 4: -0001 = 1u64
|
||||
Step 5: =0011 = 3u64
|
||||
|
||||
To make this process work for any bit-length number, where the sum of the bits is left in groups of 4 bits, we'll need to use some bit masking, so that the sum of one group of 4 does not interfere with the next group of 4.
|
||||
With a larger starting number, like 1111 0001 0111 0110, we will need the following bit maskings:
|
||||
```
|
||||
For A >> 1, we'll use 0111 0111 0111 .... (in u64, this is 8608480567731124087u64)
|
||||
For A >> 2, we'll use 0011 0011 0011 .... (in u64, this is 3689348814741910323u64)
|
||||
For A >> 3, we'll use 0001 0001 0001 .... (in u64, this is 1229782938247303441u64)
|
||||
```
|
||||
|
||||
For example, finding the sums of groups of 4 with a 16-bit number we'll call A to yield the bit sum number B:
|
||||
```
|
||||
A: 1111 0001 0111 0110
|
||||
A>>1: 0111 1000 1011 1011
|
||||
A>>2: 0011 1100 0101 1101
|
||||
A>>3: 0001 1110 0010 1110
|
||||
|
||||
A>>1: 0111 1000 1011 1011
|
||||
& 0111 0111 0111 0111:
|
||||
0111 0000 0011 0011
|
||||
|
||||
A>>2: 0011 1100 0101 1101
|
||||
& 0011 0011 0011 0011:
|
||||
0011 0000 0001 0001
|
||||
|
||||
A>>3: 0001 1110 0010 1110
|
||||
& 0001 0001 0001 0001:
|
||||
0001 0000 0000 0000
|
||||
|
||||
A - (A>>1 & 0111....) - (A>>2 & 0011....) - (A>>3 & 0001....):
|
||||
B: 0100 0001 0011 0010
|
||||
4 1 3 2
|
||||
```
|
||||
|
||||
The next step is to combine the summation of each of those 4-bit groups into sums of 8-bit groups. To do this, we'll use another bit trick. We will shift this number B to the right by 4 (B >> 4), and add that back to B. Then, we'll apply a bit masking of 0000 1111 0000 1111 .... (in u64, this is 1085102592571150095u64) to yield the sums of bits in groups of 8, a number we'll call C.
|
||||
```
|
||||
B: 0100 0001 0011 0010
|
||||
B>>4: 0000 0100 0001 0011
|
||||
0100 0101 0100 0101
|
||||
4 5 4 5
|
||||
|
||||
apply the bit mask
|
||||
0000 1111 0000 1111
|
||||
|
||||
C: 0000 0101 0000 0101
|
||||
0 5 0 5
|
||||
```
|
||||
|
||||
At this point, we've gone from a bit sum in groups of 4 to bit sums in groups of 8. That's great, but ultimately we want the total sum of bits in the original binary number. The final bit trick is to modulo C by 255. This is 2^8 - 1. For a bit of intuition, consider the number 1 0000 0001. If we take 1 0000 0001 mod 256, we're left with 1. If we take 1 0000 0001 mod 255, we're left with 2. Modding by 255 gives us the amount of bits _beyond_ the first 255 numbers, as 255 is the largest number that can be represented with 8 bits.
|
||||
|
||||
A full summary of abbreviated steps to get the bit count, starting with a 64-bit integer A (closely following the `bitcount` function in the `verify.leo` code):
|
||||
```
|
||||
let A = unsigned 64-bit integer
|
||||
let B = A - (A>>1 & 8608480567731124087u64) - (A>>2 & 3689348814741910323u64) - (A>>3 & 1229782938247303441u64)
|
||||
let C = (B - B>>4) & 1085102592571150095u64
|
||||
bit count = C mod 255u64
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Adjacency Check</summary>
|
||||
|
||||
Given a ship's placement on the board and its bitstring representation (horizontally or vertically), we can determine if the bits are adjacent. Follow the `adjacency_check` function in `verify.leo`. Given the ship of length 2, we know its horizontal bitstring is 11 (3u64) and its vertical bitstring is 100000001 (257u64). If on the board, the ship starts at the bottom right corner, its horizontal ship placement string would be:
|
||||
3u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 1 1
|
||||
```
|
||||
|
||||
Vertical ship placement:
|
||||
257u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
```
|
||||
|
||||
If we move the ship to the left one column:
|
||||
Horizontal 6u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 1 1 0
|
||||
```
|
||||
|
||||
Vertical 514u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 1 0
|
||||
0 0 0 0 0 0 1 0
|
||||
```
|
||||
|
||||
If we move the ship up one row:
|
||||
Horizontal 768u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 1 1
|
||||
0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
Vertical 65792u64
|
||||
```
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 1
|
||||
0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
We can make the observation that the original bitstring is always shifted by an integer amount to get to a new valid position on the board. Therefore, if we take the ship placement bitstring and divide by the ship bitstring (either horizontal or vertical), as long as the remaining number is a power of 2 (2^0, 2^1, 2^2, 2^3...), we know the ship's bits are adjacent.
|
||||
|
||||
To ensure that the remaining number is a power of 2, we can use a bit trick. See the bit trick for ensuring a bitstring is a power of 2 section.
|
||||
|
||||
In the code, you'll notice one extra step. Dividing a ship placement bitstring by a ship bitstring representation could result in 0, and then subtracting by 1 will result in an underflow. In that case, we know the ship placement is not valid, so we can set a number which is guaranteed to not be a power of 2.
|
||||
</details>
|
||||
|
||||
<details><summary>Splitting a row or column</summary>
|
||||
Follow the `horizontal_check` function in `verify.leo` to follow the code. Assume all the bits are adjacent (see the adjacency check section). The column case is trivial. We can be certain that if a ship bitstring splits columns, the division of that ship placement bitstring by its ship bitstring representation will not yield a power of 2, and it would have failed the adjacency check.
|
||||
|
||||
The horizontal case must be checked because a split row bitstring could still contain a ship with adjacent bits. To make this check easier, we will condense the `64` bitstring into an 8-bit bitstring by taking it modulo 255. If we assume that a bitstring is not splitting a row, then taking the ship placement bitstring modulo 255 will yield an 8-bit valid bitstring. If the original ship placement bitstring is not valid, then we will have an invalid 8-bit bitstring. E.g.:
|
||||
```
|
||||
1 1 1 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
```
|
||||
mod 255 = 11100000 (valid)
|
||||
|
||||
```
|
||||
0 0 0 0 0 0 0 1
|
||||
1 1 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0
|
||||
```
|
||||
mod 255 = 11000001 (invalid)
|
||||
|
||||
How do we know the 8 bit bitstring is valid or not? We can simply do an adjacency check, as before.
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Ensuring a bitstring is a power of 2</summary>
|
||||
|
||||
Any power of 2 will have a single bit flipped. If we subtract 1 from that number, it will result in a complementary bitstring that, bitwise-ANDed with the original, will always result in 0.
|
||||
|
||||
E.g.
|
||||
```
|
||||
8: 1000
|
||||
8-1: 0111
|
||||
8&7: 0000 == 0
|
||||
|
||||
7: 0111
|
||||
7-1: 0110
|
||||
7&6: 0110 != 0
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Validating all ships together in a single board
|
||||
|
||||
Give individual valid ship position bitstrings, we can combine all these together into a single board using bitwise OR operators. See the `create_board` function in `verify.leo` to follow the code. Once all ships are on the board, we can count the total number of bits, which should be 14 exactly for a ship of length 5, 4, 3, and 2.
|
||||
|
||||
## Ensure that players and boards cannot swap mid-game
|
||||
|
||||
Board states are represented with the board state record. Each board has a flag indicating whether a game has been started with the board. This flag is set when offering a battleship game to an opponent, or accepting a battleship game from an opponent. Move records are created only in 3 ways:
|
||||
1. Offering a battleship game creates a dummy move record that sets the two players to the addresses set in the board state record.
|
||||
2. Accepting a battleship game consumes the first dummy move record and checks that the move record contains the same two players as the board of the player accepting the game. Then, a new dummy move record is created and keeps the same two players.
|
||||
2. A move record must be consumed in order to play and create the next move record. There's a check to ensure the players in the move record matches the players in the board, and the players in the next move record are automatically set.
|
||||
|
||||
The only way moves _not_ matching a board can be combined is if the players begin multiple games with each other. As long as one player is honest and only accepts a single game with a particular opponent, only one set of moves can be played on one board between them.
|
||||
|
||||
## Ensure that each player can only move once before the next player can move
|
||||
|
||||
A move record must be consumed in order to create the next move record. The owner of the move record changes with each play. Player A must spend a move record in order to create a move record containing their fire coordinate, and that move record will be owned by Player B. Player B must spend that move record in order to create the next move record, which will belong to Player A.
|
||||
|
||||
## Enforce constraints on valid moves, and force the player to give their opponent information about their opponent's previous move in order to continue playing
|
||||
|
||||
A valid move for a player is a fire coordinate that has only one flipped bit in a u64. We can make sure only one bit is flipped with the powers of 2 bit trick. That single bit must be a coordinate that has not been played by that player before, which we check in `board.leo/update_played_tiles`.
|
||||
|
||||
In order to give their next move to their opponent, a player must call the `main.leo/play` function, which checks the opponent's fire coordinate on the current player's board. The move record being created is updated with whether that fire coordinate was a hit or a miss for the opponent.
|
||||
|
||||
## Winning the game
|
||||
|
||||
Right now, the way to check when a game has been won is to count the number of hits on your `hits_and_misses` component on your `board_state` record. Once you have 14 hits, you've won the game.
|
5
examples/battleship/board/.gitignore
vendored
5
examples/battleship/board/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
.env
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
||||
outputs/
|
@ -1,13 +0,0 @@
|
||||
# board.aleo
|
||||
|
||||
## Build Guide
|
||||
|
||||
To compile this Aleo program, run:
|
||||
```bash
|
||||
snarkvm build
|
||||
```
|
||||
|
||||
To execute this Aleo program, run:
|
||||
```bash
|
||||
snarkvm run hello
|
||||
```
|
@ -1,46 +0,0 @@
|
||||
program board.aleo;
|
||||
|
||||
record board_state:
|
||||
owner as address.private;
|
||||
hits_and_misses as u64.private;
|
||||
played_tiles as u64.private;
|
||||
ships as u64.private;
|
||||
player_1 as address.private;
|
||||
player_2 as address.private;
|
||||
game_started as boolean.private;
|
||||
|
||||
|
||||
function new_board_state:
|
||||
input r0 as u64.private;
|
||||
input r1 as address.private;
|
||||
cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
|
||||
output r2 as board_state.record;
|
||||
|
||||
|
||||
function start_board:
|
||||
input r0 as board_state.record;
|
||||
not r0.game_started into r1;
|
||||
assert.eq r1 true;
|
||||
cast r0.owner r0.hits_and_misses r0.played_tiles r0.ships r0.player_1 r0.player_2 true into r2 as board_state.record;
|
||||
output r2 as board_state.record;
|
||||
|
||||
|
||||
function update_played_tiles:
|
||||
input r0 as board_state.record;
|
||||
input r1 as u64.private;
|
||||
sub r1 1u64 into r2;
|
||||
and r1 r2 into r3;
|
||||
assert.eq r3 0u64;
|
||||
and r1 r0.played_tiles into r4;
|
||||
assert.eq r4 0u64;
|
||||
or r0.played_tiles r1 into r5;
|
||||
cast r0.owner r0.hits_and_misses r5 r0.ships r0.player_1 r0.player_2 r0.game_started into r6 as board_state.record;
|
||||
output r6 as board_state.record;
|
||||
|
||||
|
||||
function update_hits_and_misses:
|
||||
input r0 as board_state.record;
|
||||
input r1 as u64.private;
|
||||
or r0.hits_and_misses r1 into r2;
|
||||
cast r0.owner r2 r0.played_tiles r0.ships r0.player_1 r0.player_2 r0.game_started into r3 as board_state.record;
|
||||
output r3 as board_state.record;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "board.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// The program input for board/src/main.leo
|
||||
[main]
|
||||
public a: u32 = 1u32;
|
||||
b: u32 = 2u32;
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "board.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
program board.aleo {
|
||||
// Battleship boards are represented by 8x8 squares.
|
||||
// A u64 is all that is required to represent a hit or a miss on a single board.
|
||||
// Starting from the top row, left to right, a hit is 1 and a miss is 0.
|
||||
// A first move resulting in a hit in row 1, column 3 would be:
|
||||
// 00100000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
// A second u64 is needed to represent which squares have been played, with 1s being played squares and 0s being
|
||||
// unplayed squares.
|
||||
record board_state {
|
||||
owner: address,
|
||||
// The hits and misses registered on the opponent's board.
|
||||
hits_and_misses: u64,
|
||||
// The squares that have been played on the opponent's board.
|
||||
played_tiles: u64,
|
||||
// The ship bitstring representing all ship positions on your own board
|
||||
ships: u64,
|
||||
player_1: address,
|
||||
player_2: address,
|
||||
game_started: bool,
|
||||
}
|
||||
|
||||
// Returns a new board_state.
|
||||
transition new_board_state(
|
||||
ships: u64,
|
||||
opponent: address,
|
||||
) -> board_state {
|
||||
return board_state {
|
||||
owner: self.caller,
|
||||
hits_and_misses: 0u64,
|
||||
played_tiles: 0u64,
|
||||
ships,
|
||||
player_1: self.caller,
|
||||
player_2: opponent,
|
||||
game_started: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a new board state that has been started.
|
||||
// Fails if this board has been started before.
|
||||
transition start_board(
|
||||
// The record of the board to start. A board can only be started once.
|
||||
board: board_state,
|
||||
) -> board_state {
|
||||
// Ensure this board hasn't been used to start a game before.
|
||||
assert(!board.game_started);
|
||||
|
||||
return board_state {
|
||||
owner: board.owner,
|
||||
hits_and_misses: board.hits_and_misses,
|
||||
played_tiles: board.played_tiles,
|
||||
ships: board.ships,
|
||||
player_1: board.player_1,
|
||||
player_2: board.player_2,
|
||||
game_started: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a new board state record that includes all the played tiles.
|
||||
// Fails if r1 has been played before.
|
||||
transition update_played_tiles(
|
||||
// The record of the board to update.
|
||||
board: board_state,
|
||||
// The u64 equivalent of a bitstring fire coordinate to send to the opponent.
|
||||
shoot: u64,
|
||||
) -> board_state {
|
||||
// Need to make sure r1 is a valid move. Only one bit of r1 should be flipped.
|
||||
let flip_bit: u64 = shoot - 1u64;
|
||||
// bitwise and operation
|
||||
let check_move: u64 = shoot & flip_bit;
|
||||
assert_eq(check_move, 0u64);
|
||||
|
||||
// Need to make sure r1 is a valid move given the played_tiles. no bits should overlap.
|
||||
let check_tiles: u64 = shoot & board.played_tiles;
|
||||
assert_eq(check_tiles, 0u64);
|
||||
|
||||
// Update played tiles.
|
||||
let played_tiles: u64 = board.played_tiles | shoot;
|
||||
|
||||
return board_state {
|
||||
owner: board.owner,
|
||||
hits_and_misses: board.hits_and_misses,
|
||||
played_tiles,
|
||||
ships: board.ships,
|
||||
player_1: board.player_1,
|
||||
player_2: board.player_2,
|
||||
game_started: board.game_started,
|
||||
};
|
||||
}
|
||||
|
||||
// Returns a new board state record that includes all the hits and misses.
|
||||
transition update_hits_and_misses(
|
||||
// The record of the board to update.
|
||||
board: board_state,
|
||||
// The u64 equivalent of a bitstring of whether this player's previous move was a hit or miss.
|
||||
hit_or_miss: u64,
|
||||
) -> board_state {
|
||||
// Update hits and misses.
|
||||
let hits_and_misses: u64 = board.hits_and_misses | hit_or_miss;
|
||||
|
||||
return board_state {
|
||||
owner: board.owner,
|
||||
hits_and_misses,
|
||||
played_tiles: board.played_tiles,
|
||||
ships: board.ships,
|
||||
player_1: board.player_1,
|
||||
player_2: board.player_2,
|
||||
game_started: board.game_started,
|
||||
};
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
program board.aleo;
|
||||
|
||||
record board_state:
|
||||
owner as address.private;
|
||||
hits_and_misses as u64.private;
|
||||
played_tiles as u64.private;
|
||||
ships as u64.private;
|
||||
player_1 as address.private;
|
||||
player_2 as address.private;
|
||||
game_started as boolean.private;
|
||||
|
||||
|
||||
function new_board_state:
|
||||
input r0 as u64.private;
|
||||
input r1 as address.private;
|
||||
cast self.caller 0u64 0u64 r0 self.caller r1 false into r2 as board_state.record;
|
||||
output r2 as board_state.record;
|
||||
|
||||
|
||||
function start_board:
|
||||
input r0 as board_state.record;
|
||||
not r0.game_started into r1;
|
||||
assert.eq r1 true;
|
||||
cast r0.owner r0.hits_and_misses r0.played_tiles r0.ships r0.player_1 r0.player_2 true into r2 as board_state.record;
|
||||
output r2 as board_state.record;
|
||||
|
||||
|
||||
function update_played_tiles:
|
||||
input r0 as board_state.record;
|
||||
input r1 as u64.private;
|
||||
sub r1 1u64 into r2;
|
||||
and r1 r2 into r3;
|
||||
assert.eq r3 0u64;
|
||||
and r1 r0.played_tiles into r4;
|
||||
assert.eq r4 0u64;
|
||||
or r0.played_tiles r1 into r5;
|
||||
cast r0.owner r0.hits_and_misses r5 r0.ships r0.player_1 r0.player_2 r0.game_started into r6 as board_state.record;
|
||||
output r6 as board_state.record;
|
||||
|
||||
|
||||
function update_hits_and_misses:
|
||||
input r0 as board_state.record;
|
||||
input r1 as u64.private;
|
||||
or r0.hits_and_misses r1 into r2;
|
||||
cast r0.owner r2 r0.played_tiles r0.ships r0.player_1 r0.player_2 r0.game_started into r3 as board_state.record;
|
||||
output r3 as board_state.record;
|
@ -1,24 +0,0 @@
|
||||
program move.aleo;
|
||||
|
||||
record move:
|
||||
owner as address.private;
|
||||
incoming_fire_coordinate as u64.private;
|
||||
player_1 as address.private;
|
||||
player_2 as address.private;
|
||||
prev_hit_or_miss as u64.private;
|
||||
|
||||
|
||||
function create_move:
|
||||
input r0 as move.record;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
is.eq r0.player_1 r0.owner into r3;
|
||||
ternary r3 r0.player_2 r0.player_1 into r4;
|
||||
cast r4 r1 r0.player_2 r0.player_1 r2 into r5 as move.record;
|
||||
output r5 as move.record;
|
||||
|
||||
|
||||
function start_game:
|
||||
input r0 as address.private;
|
||||
cast r0 0u64 self.caller r0 0u64 into r1 as move.record;
|
||||
output r1 as move.record;
|
@ -1,73 +0,0 @@
|
||||
program verify.aleo;
|
||||
|
||||
|
||||
|
||||
closure bitcount:
|
||||
input r0 as u64;
|
||||
div r0 2u64 into r1;
|
||||
div r0 4u64 into r2;
|
||||
div r0 8u64 into r3;
|
||||
and r1 8608480567731124087u64 into r4;
|
||||
and r2 3689348814741910323u64 into r5;
|
||||
and r3 1229782938247303441u64 into r6;
|
||||
sub r0 r4 into r7;
|
||||
sub r7 r5 into r8;
|
||||
sub r8 r6 into r9;
|
||||
div r9 16u64 into r10;
|
||||
add r9 r10 into r11;
|
||||
and r11 1085102592571150095u64 into r12;
|
||||
rem r12 255u64 into r13;
|
||||
output r13 as u64;
|
||||
|
||||
|
||||
closure adjacency_check:
|
||||
input r0 as u64;
|
||||
input r1 as u64;
|
||||
div r0 r1 into r2;
|
||||
is.eq r2 0u64 into r3;
|
||||
ternary r3 3u64 r2 into r4;
|
||||
sub r4 1u64 into r5;
|
||||
and r5 r4 into r6;
|
||||
is.eq r6 0u64 into r7;
|
||||
output r7 as boolean;
|
||||
|
||||
|
||||
closure horizontal_check:
|
||||
input r0 as u64;
|
||||
input r1 as u64;
|
||||
rem r0 255u64 into r2;
|
||||
div r2 r1 into r3;
|
||||
is.eq r3 0u64 into r4;
|
||||
ternary r4 3u64 r3 into r5;
|
||||
sub r5 1u64 into r6;
|
||||
and r6 r5 into r7;
|
||||
is.eq r7 0u64 into r8;
|
||||
output r8 as boolean;
|
||||
|
||||
|
||||
function validate_ship:
|
||||
input r0 as u64.private;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
input r3 as u64.private;
|
||||
call bitcount r0 into r4;
|
||||
assert.eq r4 r1;
|
||||
call adjacency_check r0 r2 into r5;
|
||||
call horizontal_check r0 r2 into r6;
|
||||
and r5 r6 into r7;
|
||||
call adjacency_check r0 r3 into r8;
|
||||
or r7 r8 into r9;
|
||||
output r9 as boolean.private;
|
||||
|
||||
|
||||
function create_board:
|
||||
input r0 as u64.private;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
input r3 as u64.private;
|
||||
or r0 r1 into r4;
|
||||
or r4 r2 into r5;
|
||||
or r5 r3 into r6;
|
||||
call bitcount r6 into r7;
|
||||
assert.eq r7 14u64;
|
||||
output r6 as u64.private;
|
@ -1,59 +0,0 @@
|
||||
import board.aleo;
|
||||
import move.aleo;
|
||||
import verify.aleo;
|
||||
program battleship.aleo;
|
||||
|
||||
|
||||
|
||||
|
||||
function initialize_board:
|
||||
input r0 as u64.private;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
input r3 as u64.private;
|
||||
input r4 as address.private;
|
||||
call verify.aleo/validate_ship r0 5u64 31u64 4311810305u64 into r5;
|
||||
assert.eq r5 true;
|
||||
call verify.aleo/validate_ship r1 4u64 15u64 16843009u64 into r6;
|
||||
assert.eq r6 true;
|
||||
call verify.aleo/validate_ship r2 3u64 7u64 65793u64 into r7;
|
||||
assert.eq r7 true;
|
||||
call verify.aleo/validate_ship r3 2u64 3u64 257u64 into r8;
|
||||
assert.eq r8 true;
|
||||
call verify.aleo/create_board r0 r1 r2 r3 into r9;
|
||||
call board.aleo/new_board_state r9 r4 into r10;
|
||||
output r10 as board.aleo/board_state.record;
|
||||
|
||||
|
||||
function offer_battleship:
|
||||
input r0 as board.aleo/board_state.record;
|
||||
call board.aleo/start_board r0 into r1;
|
||||
call move.aleo/start_game r0.player_2 into r2;
|
||||
output r1 as board.aleo/board_state.record;
|
||||
output r2 as move.aleo/move.record;
|
||||
|
||||
|
||||
function start_battleship:
|
||||
input r0 as board.aleo/board_state.record;
|
||||
input r1 as move.aleo/move.record;
|
||||
assert.eq r0.player_1 r1.player_2;
|
||||
assert.eq r0.player_2 r1.player_1;
|
||||
call board.aleo/start_board r0 into r2;
|
||||
call move.aleo/start_game r0.player_2 into r3;
|
||||
output r2 as board.aleo/board_state.record;
|
||||
output r3 as move.aleo/move.record;
|
||||
|
||||
|
||||
function play:
|
||||
input r0 as board.aleo/board_state.record;
|
||||
input r1 as move.aleo/move.record;
|
||||
input r2 as u64.private;
|
||||
assert.eq r0.game_started true;
|
||||
assert.eq r0.player_1 r1.player_2;
|
||||
assert.eq r0.player_2 r1.player_1;
|
||||
call board.aleo/update_played_tiles r0 r2 into r3;
|
||||
call board.aleo/update_hits_and_misses r3 r1.prev_hit_or_miss into r4;
|
||||
and r1.incoming_fire_coordinate r0.ships into r5;
|
||||
call move.aleo/create_move r1 r2 r5 into r6;
|
||||
output r4 as board.aleo/board_state.record;
|
||||
output r6 as move.aleo/move.record;
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"program": "battleship.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"dependencies" : [
|
||||
{
|
||||
"name": "board.aleo",
|
||||
"location": "local",
|
||||
"path": "board"
|
||||
},
|
||||
{
|
||||
"name": "move.aleo",
|
||||
"location": "local",
|
||||
"path": "move"
|
||||
},
|
||||
{
|
||||
"name": "verify.aleo",
|
||||
"location": "local",
|
||||
"path": "verify"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 159 KiB |
5
examples/battleship/move/.gitignore
vendored
5
examples/battleship/move/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
.env
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
||||
outputs/
|
@ -1,13 +0,0 @@
|
||||
# move.aleo
|
||||
|
||||
## Build Guide
|
||||
|
||||
To compile this Aleo program, run:
|
||||
```bash
|
||||
snarkvm build
|
||||
```
|
||||
|
||||
To execute this Aleo program, run:
|
||||
```bash
|
||||
snarkvm run hello
|
||||
```
|
@ -1,24 +0,0 @@
|
||||
program move.aleo;
|
||||
|
||||
record move:
|
||||
owner as address.private;
|
||||
incoming_fire_coordinate as u64.private;
|
||||
player_1 as address.private;
|
||||
player_2 as address.private;
|
||||
prev_hit_or_miss as u64.private;
|
||||
|
||||
|
||||
function create_move:
|
||||
input r0 as move.record;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
is.eq r0.player_1 r0.owner into r3;
|
||||
ternary r3 r0.player_2 r0.player_1 into r4;
|
||||
cast r4 r1 r0.player_2 r0.player_1 r2 into r5 as move.record;
|
||||
output r5 as move.record;
|
||||
|
||||
|
||||
function start_game:
|
||||
input r0 as address.private;
|
||||
cast r0 0u64 self.caller r0 0u64 into r1 as move.record;
|
||||
output r1 as move.record;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "move.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// The program input for move/src/main.leo
|
||||
[main]
|
||||
public a: u32 = 1u32;
|
||||
b: u32 = 2u32;
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "move.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
program move.aleo {
|
||||
record move {
|
||||
owner: address,
|
||||
incoming_fire_coordinate: u64,
|
||||
player_1: address,
|
||||
player_2: address,
|
||||
// One flipped bit indicates a hit. No flipped bits indicates a miss.
|
||||
prev_hit_or_miss: u64,
|
||||
}
|
||||
|
||||
// Returns new move record owned by the opponent.
|
||||
transition create_move(
|
||||
// The move record created by the opponent.
|
||||
move_record: move,
|
||||
// The u64 representation of incoming_fire_coordinate, the bitstring fire coordinate to send to the opponent.
|
||||
incoming_fire_coordinate: u64,
|
||||
// The u64 representation of prev_hit_or_miss, this player's previous fire coordinate as a hit or miss.
|
||||
prev_hit_or_miss: u64,
|
||||
) -> move {
|
||||
// A new move record should be created and owned by the opponent.
|
||||
let one_is_owner: bool = move_record.player_1 == move_record.owner;
|
||||
let opponent: address = one_is_owner ? move_record.player_2 : move_record.player_1;
|
||||
|
||||
return move {
|
||||
owner: opponent,
|
||||
incoming_fire_coordinate,
|
||||
player_1: move_record.player_2,
|
||||
player_2: move_record.player_1,
|
||||
prev_hit_or_miss,
|
||||
};
|
||||
}
|
||||
|
||||
// Returns the move record owned by the opponent.
|
||||
// Note, this move record contains dummy fire coordinates and previous hit or miss.
|
||||
transition start_game(player_2: address) -> move {
|
||||
return move {
|
||||
owner: player_2,
|
||||
incoming_fire_coordinate: 0u64,
|
||||
player_1: self.caller,
|
||||
player_2: player_2,
|
||||
prev_hit_or_miss: 0u64,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"program": "battleship.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"dependencies" : [
|
||||
{
|
||||
"name": "board.aleo",
|
||||
"location": "local",
|
||||
"path": "board"
|
||||
},
|
||||
{
|
||||
"name": "move.aleo",
|
||||
"location": "local",
|
||||
"path": "move"
|
||||
},
|
||||
{
|
||||
"name": "verify.aleo",
|
||||
"location": "local",
|
||||
"path": "verify"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
#!/bin/bash
|
||||
# First check that Leo is installed.
|
||||
if ! command -v leo &> /dev/null
|
||||
then
|
||||
echo "leo is not installed."
|
||||
exit
|
||||
fi
|
||||
# Follow along in the README.md for a detailed explanation of each step.
|
||||
|
||||
# 1: Initializing Player 1
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 1: Initializing Player 1 ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
echo "✅ Successfully initialized Player 1."
|
||||
|
||||
# 2: Player 1 Places Ships On The Board
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 2: Player 1 Places Ships On The Board ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run initialize_board 34084860461056u64 551911718912u64 7u64 1157425104234217472u64 aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px || exit
|
||||
|
||||
echo "
|
||||
✅ Successfully initialized Player 1's board."
|
||||
|
||||
# 3: Player 1 Passes The Board To Player 2
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 3: Player 1 Passes The Board To Player 2 ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
leo run offer_battleship '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: false.private,
|
||||
_nonce: 3887646704618532506963887075433683846689834495661101507703164090915348189037group.public
|
||||
}' || exit
|
||||
echo "
|
||||
✅ Successfully passed the board to Player 2."
|
||||
|
||||
# 4: Player 2 Places Ships On The Board
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 4: Player 2 Places Ships On The Board ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
leo run initialize_board 31u64 2207646875648u64 224u64 9042383626829824u64 aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t || exit
|
||||
|
||||
echo "
|
||||
✅ Successfully initialized Player 2's board."
|
||||
|
||||
# 5: Passing The Board Back To Player 1
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 5: Passing The Board Back To Player 1 ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
|
||||
"
|
||||
leo run start_battleship '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: false.private,
|
||||
_nonce: 1549419609469324182591325047490602235361156298832591378925133482196483208807group.public
|
||||
}' '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 0u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 4374626042494973146987320062571809401151262172766172816829659487584978644457group.public
|
||||
}' || exit
|
||||
echo "
|
||||
✅ Successfully passed the board back to Player 1."
|
||||
|
||||
# 6: Player 1 Takes The 1st Turn
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 6: Player 1 Takes The 1st Turn ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
leo run play '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 6563064852163330630334088854834332804417910882908622526775624018226782316843group.public
|
||||
}' '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 0u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 3742551407126138397717446975757978589064777004441277005584760115236217735495group.public
|
||||
}' 1u64 || exit
|
||||
|
||||
echo "
|
||||
✅ Successfully executed Player 1's turn."
|
||||
|
||||
# 7: Player 2 Takes The 2nd Turn
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 7: Player 2 Takes The 2nd Turn ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
leo run play '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 0u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 6222383571142756260765569201308836492199048237638652378826141459336360362251group.public
|
||||
}' '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 1u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 5481529266389297320813092061136936339861329677911328036818179854958874588416group.public
|
||||
}' 2048u64 || exit
|
||||
|
||||
echo "
|
||||
✅ Successfully executed Player 2's turn."
|
||||
|
||||
# 8: Player 1 Takes The 3rd Turn
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 8: Player 1 Takes The 3rd Turn ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
leo run play '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 1u64.private,
|
||||
ships: 1157459741006397447u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 1474170213684980843727833284550698461565286563122422722760769547002894080093group.public
|
||||
}' '{
|
||||
owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
incoming_fire_coordinate: 2048u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 1u64.private,
|
||||
_nonce: 5851606198769770675504009323414373017067582072428989801313256693053765675198group.public
|
||||
}' 2u64 || exit
|
||||
|
||||
echo "
|
||||
✅ Successfully executed Player 1's turn."
|
||||
|
||||
# 9: Player 2 Takes The 4th Turn
|
||||
echo "
|
||||
###############################################################################
|
||||
######## ########
|
||||
######## STEP 9: Player 2 Takes The 4th Turn ########
|
||||
######## ########
|
||||
###############################################################################
|
||||
"
|
||||
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp2RWGDcde3efb89rjhME1VYA8QMxcxep5DShNBR6n8Yjh
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
||||
|
||||
leo run play '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
hits_and_misses: 0u64.private,
|
||||
played_tiles: 2048u64.private,
|
||||
ships: 9044591273705727u64.private,
|
||||
player_1: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
player_2: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
game_started: true.private,
|
||||
_nonce: 5254963165391133332409074172682159033621708071536429341861038147524454777097group.public
|
||||
}' '{
|
||||
owner: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
incoming_fire_coordinate: 2u64.private,
|
||||
player_1: aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t.private,
|
||||
player_2: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private,
|
||||
prev_hit_or_miss: 0u64.private,
|
||||
_nonce: 710336412388939616658264778971886770861024495941253598683184288448156545822group.public
|
||||
}' 4u64 || exit
|
||||
|
||||
echo "
|
||||
✅ Successfully executed Player 2's turn."
|
||||
|
||||
|
||||
# Restore the .env file to its original state
|
||||
echo "
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
||||
" > .env
|
@ -1,105 +0,0 @@
|
||||
import board.aleo;
|
||||
import move.aleo;
|
||||
import verify.aleo;
|
||||
|
||||
// The 'battleship.aleo' program.
|
||||
program battleship.aleo {
|
||||
// Returns a new record representing a new game of battleship.
|
||||
transition initialize_board(
|
||||
// The u64 representation of a carrier's placement in an 8x8 grid. Length = 5.
|
||||
carrier: u64,
|
||||
// The u64 representation of a battleship's placement in an 8x8 grid. Length = 4.
|
||||
battleship: u64,
|
||||
// The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3.
|
||||
cruiser: u64,
|
||||
// The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2.
|
||||
destroyer: u64,
|
||||
// The address of the opponent.
|
||||
player: address,
|
||||
) -> board.aleo/board_state {
|
||||
// Verify that each individual ship placement bitstring is valid.
|
||||
let valid_carrier: bool = verify.aleo/validate_ship(carrier, 5u64, 31u64, 4311810305u64);
|
||||
assert(valid_carrier);
|
||||
|
||||
let valid_battleship: bool = verify.aleo/validate_ship(battleship, 4u64, 15u64, 16843009u64);
|
||||
assert(valid_battleship);
|
||||
|
||||
let valid_cruiser: bool = verify.aleo/validate_ship(cruiser, 3u64, 7u64, 65793u64);
|
||||
assert(valid_cruiser);
|
||||
|
||||
let valid_destroyer: bool = verify.aleo/validate_ship(destroyer, 2u64, 3u64, 257u64);
|
||||
assert(valid_destroyer);
|
||||
|
||||
// Create the board with all the ship placements combined.
|
||||
let board: u64 = verify.aleo/create_board(carrier, battleship, cruiser, destroyer);
|
||||
|
||||
// Initialize the board state record.
|
||||
let state: board.aleo/board_state = board.aleo/new_board_state(board, player);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
// Returns an updated board state record that has been started. This board cannot be used to start any other games.
|
||||
// Returns a dummy move record owned by the opponent.
|
||||
// This function commits a given board to a game with an opponent and creates the initial dummy move.
|
||||
transition offer_battleship(
|
||||
// The board record to start a game with.
|
||||
board: board.aleo/board_state,
|
||||
) -> (board.aleo/board_state, move.aleo/move) {
|
||||
let state: board.aleo/board_state = board.aleo/start_board(board);
|
||||
let dummy: move.aleo/move = move.aleo/start_game(board.player_2);
|
||||
|
||||
return (state, dummy);
|
||||
}
|
||||
|
||||
// Returns updated board_state that has been started and can no longer be used to join or start new games.
|
||||
// Returns dummy move record owned by the opponent.
|
||||
transition start_battleship(
|
||||
// The board record to play the game with.
|
||||
board: board.aleo/board_state,
|
||||
// The move record to play to begin the game. This should be the dummy move record created from offer_battleship.
|
||||
move_start: move.aleo/move,
|
||||
) -> (board.aleo/board_state, move.aleo/move) {
|
||||
// Validate that the move players and board players match each other.
|
||||
assert_eq(board.player_1, move_start.player_2);
|
||||
assert_eq(board.player_2, move_start.player_1);
|
||||
|
||||
let state: board.aleo/board_state = board.aleo/start_board(board);
|
||||
let dummy: move.aleo/move = move.aleo/start_game(board.player_2);
|
||||
|
||||
return (state, dummy);
|
||||
}
|
||||
|
||||
// Returns updated board record.
|
||||
// Returns new move record owned by opponent.
|
||||
transition play(
|
||||
// The board record to update.
|
||||
board: board.aleo/board_state,
|
||||
// The incoming move from the opponent.
|
||||
move_incoming: move.aleo/move,
|
||||
// The u64 equivalent of the bitwise representation of the next coordinate to play on the opponent's board.
|
||||
shoot: u64,
|
||||
) -> (board.aleo/board_state, move.aleo/move) {
|
||||
// Verify the board has been started. This prevents players from starting a game and then creating
|
||||
// a brand new board to play with.
|
||||
assert(board.game_started);
|
||||
|
||||
// Validate that the move players and board players match each other.
|
||||
assert_eq(board.player_1, move_incoming.player_2);
|
||||
assert_eq(board.player_2, move_incoming.player_1);
|
||||
|
||||
// Play coordinate on own board. Will fail if not a valid move.
|
||||
let hit_or_miss: board.aleo/board_state = board.aleo/update_played_tiles(board, shoot);
|
||||
|
||||
// Update own board with result of last shot.
|
||||
let next_board: board.aleo/board_state = board.aleo/update_hits_and_misses(hit_or_miss, move_incoming.prev_hit_or_miss);
|
||||
|
||||
// Assess whether incoming fire coordinate is a hit.
|
||||
let is_hit: u64 = move_incoming.incoming_fire_coordinate & board.ships;
|
||||
|
||||
let next_move: move.aleo/move = move.aleo/create_move(move_incoming, shoot, is_hit);
|
||||
|
||||
return (next_board, next_move);
|
||||
}
|
||||
}
|
||||
|
5
examples/battleship/verify/.gitignore
vendored
5
examples/battleship/verify/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
.env
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
||||
outputs/
|
@ -1,13 +0,0 @@
|
||||
# verify.aleo
|
||||
|
||||
## Build Guide
|
||||
|
||||
To compile this Aleo program, run:
|
||||
```bash
|
||||
snarkvm build
|
||||
```
|
||||
|
||||
To execute this Aleo program, run:
|
||||
```bash
|
||||
snarkvm run hello
|
||||
```
|
@ -1,73 +0,0 @@
|
||||
program verify.aleo;
|
||||
|
||||
|
||||
|
||||
closure bitcount:
|
||||
input r0 as u64;
|
||||
div r0 2u64 into r1;
|
||||
div r0 4u64 into r2;
|
||||
div r0 8u64 into r3;
|
||||
and r1 8608480567731124087u64 into r4;
|
||||
and r2 3689348814741910323u64 into r5;
|
||||
and r3 1229782938247303441u64 into r6;
|
||||
sub r0 r4 into r7;
|
||||
sub r7 r5 into r8;
|
||||
sub r8 r6 into r9;
|
||||
div r9 16u64 into r10;
|
||||
add r9 r10 into r11;
|
||||
and r11 1085102592571150095u64 into r12;
|
||||
rem r12 255u64 into r13;
|
||||
output r13 as u64;
|
||||
|
||||
|
||||
closure adjacency_check:
|
||||
input r0 as u64;
|
||||
input r1 as u64;
|
||||
div r0 r1 into r2;
|
||||
is.eq r2 0u64 into r3;
|
||||
ternary r3 3u64 r2 into r4;
|
||||
sub r4 1u64 into r5;
|
||||
and r5 r4 into r6;
|
||||
is.eq r6 0u64 into r7;
|
||||
output r7 as boolean;
|
||||
|
||||
|
||||
closure horizontal_check:
|
||||
input r0 as u64;
|
||||
input r1 as u64;
|
||||
rem r0 255u64 into r2;
|
||||
div r2 r1 into r3;
|
||||
is.eq r3 0u64 into r4;
|
||||
ternary r4 3u64 r3 into r5;
|
||||
sub r5 1u64 into r6;
|
||||
and r6 r5 into r7;
|
||||
is.eq r7 0u64 into r8;
|
||||
output r8 as boolean;
|
||||
|
||||
|
||||
function validate_ship:
|
||||
input r0 as u64.private;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
input r3 as u64.private;
|
||||
call bitcount r0 into r4;
|
||||
assert.eq r4 r1;
|
||||
call adjacency_check r0 r2 into r5;
|
||||
call horizontal_check r0 r2 into r6;
|
||||
and r5 r6 into r7;
|
||||
call adjacency_check r0 r3 into r8;
|
||||
or r7 r8 into r9;
|
||||
output r9 as boolean.private;
|
||||
|
||||
|
||||
function create_board:
|
||||
input r0 as u64.private;
|
||||
input r1 as u64.private;
|
||||
input r2 as u64.private;
|
||||
input r3 as u64.private;
|
||||
or r0 r1 into r4;
|
||||
or r4 r2 into r5;
|
||||
or r5 r3 into r6;
|
||||
call bitcount r6 into r7;
|
||||
assert.eq r7 14u64;
|
||||
output r6 as u64.private;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "verify.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// The program input for verify/src/main.leo
|
||||
[main]
|
||||
public a: u32 = 1u32;
|
||||
b: u32 = 2u32;
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "verify.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
program verify.aleo {
|
||||
// Returns the number of flipped bits.
|
||||
// E.g. 17870283321406128128u64, in binary 11111000 00000000 00000000 00000000 00000000 00000000 00000000 00000000,
|
||||
// returns 5u64;
|
||||
function bitcount(bits: u64) -> u64 {
|
||||
let r1: u64 = bits / 2u64;
|
||||
let r2: u64 = bits / 4u64;
|
||||
let r3: u64 = bits / 8u64;
|
||||
|
||||
let r4: u64 = r1 & 8608480567731124087u64;
|
||||
let r5: u64 = r2 & 3689348814741910323u64;
|
||||
let r6: u64 = r3 & 1229782938247303441u64;
|
||||
|
||||
let r7: u64 = bits - r4 - r5 - r6;
|
||||
|
||||
let r8: u64 = r7 / 16u64;
|
||||
let r9: u64 = r7 + r8;
|
||||
let r10: u64 = r9 & 1085102592571150095u64;
|
||||
let r11: u64 = r10 % 255u64;
|
||||
|
||||
return r11;
|
||||
}
|
||||
|
||||
// Returns boolean of whether all the flipped bits in location are "adjacent". Horizontally, this means all flipped bits are
|
||||
// directly next to each other (111). Vertically, this means all flipped bits are separated by 7 unflipped bits
|
||||
// (10000000100000001).
|
||||
function adjacency_check(
|
||||
// The u64 representation of a ship's placement in an 8x8 grid.
|
||||
ship: u64,
|
||||
// The u64 representation of a ship's bitstring, either horizontally or vertically.
|
||||
// E.g. a ship of length 3's bit string horizontally would be: 000111 = 7u64. Vertically, the bit string would be:
|
||||
// 10000000100000001 = 65793u64.
|
||||
orientation: u64,
|
||||
) -> bool {
|
||||
// This may result in 0.
|
||||
let division: u64 = ship / orientation;
|
||||
|
||||
// subtracting 1 from 0 will cause an underflow, so we should check for this edge case.
|
||||
let is_eq: bool = division == 0u64;
|
||||
|
||||
// if the above division resulted in 0, we know the adjacency check should return false.
|
||||
// Setting to r4 to 3 (11) will guarantee failure here.
|
||||
let ternary: u64 = is_eq ? 3u64 : division;
|
||||
let subtraction: u64 = ternary - 1u64;
|
||||
let and: u64 = subtraction & ternary;
|
||||
|
||||
let bits_are_adjacent: bool = and == 0u64;
|
||||
|
||||
return bits_are_adjacent;
|
||||
}
|
||||
|
||||
// Returns boolean of whether adjacent flipped bits don't split a row of size 8.
|
||||
// E.g. 111000000 has adjacent flipped bits but splits a row: 00000001 11000000
|
||||
function horizontal_check(
|
||||
// The u64 representation of a ship's placement in an 8x8 grid.
|
||||
ship: u64,
|
||||
// The u64 representation of a ship's bitstring horizontally.
|
||||
horizontal: u64,
|
||||
) -> bool {
|
||||
let remainder: u64 = ship % 255u64;
|
||||
// This may result in 0.
|
||||
let division: u64 = remainder / horizontal;
|
||||
|
||||
// Subtracting 1 from 0 will cause an underflow.
|
||||
let is_eq: bool = division == 0u64;
|
||||
|
||||
// Setting to 3 will guarantee failure.
|
||||
let ternary: u64 = is_eq ? 3u64 : division;
|
||||
let subtraction: u64 = ternary - 1u64;
|
||||
let and: u64 = subtraction & ternary;
|
||||
|
||||
let bits_split_row: bool = and == 0u64;
|
||||
|
||||
return bits_split_row;
|
||||
}
|
||||
|
||||
// Returns `true` if the ship placement is valid.
|
||||
transition validate_ship(
|
||||
// The u64 representation of a ship's placement in an 8x8 grid.
|
||||
ship: u64,
|
||||
// The length of the placed ship.
|
||||
length: u64,
|
||||
// The u64 equivalent of a ship's horizontal bitstring representation.
|
||||
horizontal: u64,
|
||||
// The u64 equivalent of a ship's vertical bitstring representation.
|
||||
vertical: u64,
|
||||
) -> bool {
|
||||
// Check bitcount -- all other validations depend on the bitcount being correct.
|
||||
let num_bits: u64 = bitcount(ship);
|
||||
assert_eq(num_bits, length);
|
||||
|
||||
// Check horizontal bits of ship.
|
||||
let is_adjacent: bool = adjacency_check(ship, horizontal); // True if bits are adjacent horizontally.
|
||||
let is_horizontal: bool = horizontal_check(ship, horizontal); // True if those horizontal bits are not split across rows.
|
||||
let valid_horizontal: bool = is_adjacent && is_horizontal; // True if bits are adjacent horizontally and not split across rows.
|
||||
|
||||
// Check vertical bits of ship.
|
||||
let valid_vertical: bool = adjacency_check(ship, vertical); // True if bits are adjacent vertically.
|
||||
|
||||
let ship_is_valid: bool = valid_horizontal || valid_vertical; // Ship is valid if it is vertically or horizontally valid.
|
||||
|
||||
return ship_is_valid;
|
||||
}
|
||||
|
||||
// Returns the u64 representation of all the ships' placements in an 8x8 grid. This function will fail
|
||||
// if any of the ship placements overlap each other.
|
||||
transition create_board(
|
||||
// The u64 representation of a carrier's placement in an 8x8 grid. Length = 5.
|
||||
carrier: u64,
|
||||
// The u64 representation of a battleship's placement in an 8x8 grid. Length = 4.
|
||||
battleship: u64,
|
||||
// The u64 representation of a cruiser's placement in an 8x8 grid. Length = 3.
|
||||
cruiser: u64,
|
||||
// The u64 representation of a destroyer's placement in an 8x8 grid. Length = 2.
|
||||
destroyer: u64,
|
||||
) -> u64 {
|
||||
// Bitwise combine the ship placements together
|
||||
let ships: u64 = carrier | battleship | cruiser | destroyer;
|
||||
|
||||
let num_bits: u64 = bitcount(ships);
|
||||
assert_eq(num_bits, 14u64); // Given 4 individually-valid ships, a valid combination should yield exactly 14 flipped bits.
|
||||
|
||||
return ships;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
3
examples/bubblesort/.gitignore
vendored
3
examples/bubblesort/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
outputs/
|
||||
*.prover
|
||||
*.verifier
|
@ -1,21 +0,0 @@
|
||||
# bubblesort
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run this program, run:
|
||||
```bash
|
||||
leo run bubble_sort <inputs>
|
||||
```
|
||||
|
||||
## Execute Guide
|
||||
|
||||
To execute this program, run:
|
||||
```bash
|
||||
leo execute bubble_sort <inputs>
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
This example shows how to sort an array.
|
||||
|
||||
It takes the input data from inputs/bubblesort.in
|
Binary file not shown.
@ -1,105 +0,0 @@
|
||||
program bubblesort.aleo;
|
||||
|
||||
|
||||
|
||||
function bubble_sort:
|
||||
input r0 as u32.private;
|
||||
input r1 as u32.private;
|
||||
input r2 as u32.private;
|
||||
input r3 as u32.private;
|
||||
input r4 as u32.private;
|
||||
input r5 as u32.private;
|
||||
input r6 as u32.private;
|
||||
input r7 as u32.private;
|
||||
lt r1 r0 into r8;
|
||||
ternary r8 r1 r0 into r9;
|
||||
ternary r8 r0 r1 into r10;
|
||||
lt r2 r10 into r11;
|
||||
ternary r11 r2 r10 into r12;
|
||||
ternary r11 r10 r2 into r13;
|
||||
lt r3 r13 into r14;
|
||||
ternary r14 r3 r13 into r15;
|
||||
ternary r14 r13 r3 into r16;
|
||||
lt r4 r16 into r17;
|
||||
ternary r17 r4 r16 into r18;
|
||||
ternary r17 r16 r4 into r19;
|
||||
lt r5 r19 into r20;
|
||||
ternary r20 r5 r19 into r21;
|
||||
ternary r20 r19 r5 into r22;
|
||||
lt r6 r22 into r23;
|
||||
ternary r23 r6 r22 into r24;
|
||||
ternary r23 r22 r6 into r25;
|
||||
lt r7 r25 into r26;
|
||||
ternary r26 r7 r25 into r27;
|
||||
ternary r26 r25 r7 into r28;
|
||||
lt r12 r9 into r29;
|
||||
ternary r29 r12 r9 into r30;
|
||||
ternary r29 r9 r12 into r31;
|
||||
lt r15 r31 into r32;
|
||||
ternary r32 r15 r31 into r33;
|
||||
ternary r32 r31 r15 into r34;
|
||||
lt r18 r34 into r35;
|
||||
ternary r35 r18 r34 into r36;
|
||||
ternary r35 r34 r18 into r37;
|
||||
lt r21 r37 into r38;
|
||||
ternary r38 r21 r37 into r39;
|
||||
ternary r38 r37 r21 into r40;
|
||||
lt r24 r40 into r41;
|
||||
ternary r41 r24 r40 into r42;
|
||||
ternary r41 r40 r24 into r43;
|
||||
lt r27 r43 into r44;
|
||||
ternary r44 r27 r43 into r45;
|
||||
ternary r44 r43 r27 into r46;
|
||||
lt r33 r30 into r47;
|
||||
ternary r47 r33 r30 into r48;
|
||||
ternary r47 r30 r33 into r49;
|
||||
lt r36 r49 into r50;
|
||||
ternary r50 r36 r49 into r51;
|
||||
ternary r50 r49 r36 into r52;
|
||||
lt r39 r52 into r53;
|
||||
ternary r53 r39 r52 into r54;
|
||||
ternary r53 r52 r39 into r55;
|
||||
lt r42 r55 into r56;
|
||||
ternary r56 r42 r55 into r57;
|
||||
ternary r56 r55 r42 into r58;
|
||||
lt r45 r58 into r59;
|
||||
ternary r59 r45 r58 into r60;
|
||||
ternary r59 r58 r45 into r61;
|
||||
lt r51 r48 into r62;
|
||||
ternary r62 r51 r48 into r63;
|
||||
ternary r62 r48 r51 into r64;
|
||||
lt r54 r64 into r65;
|
||||
ternary r65 r54 r64 into r66;
|
||||
ternary r65 r64 r54 into r67;
|
||||
lt r57 r67 into r68;
|
||||
ternary r68 r57 r67 into r69;
|
||||
ternary r68 r67 r57 into r70;
|
||||
lt r60 r70 into r71;
|
||||
ternary r71 r60 r70 into r72;
|
||||
ternary r71 r70 r60 into r73;
|
||||
lt r66 r63 into r74;
|
||||
ternary r74 r66 r63 into r75;
|
||||
ternary r74 r63 r66 into r76;
|
||||
lt r69 r76 into r77;
|
||||
ternary r77 r69 r76 into r78;
|
||||
ternary r77 r76 r69 into r79;
|
||||
lt r72 r79 into r80;
|
||||
ternary r80 r72 r79 into r81;
|
||||
ternary r80 r79 r72 into r82;
|
||||
lt r78 r75 into r83;
|
||||
ternary r83 r78 r75 into r84;
|
||||
ternary r83 r75 r78 into r85;
|
||||
lt r81 r85 into r86;
|
||||
ternary r86 r81 r85 into r87;
|
||||
ternary r86 r85 r81 into r88;
|
||||
lt r87 r84 into r89;
|
||||
ternary r89 r87 r84 into r90;
|
||||
ternary r89 r84 r87 into r91;
|
||||
output r90 as u32.private;
|
||||
output r91 as u32.private;
|
||||
output r88 as u32.private;
|
||||
output r82 as u32.private;
|
||||
output r73 as u32.private;
|
||||
output r61 as u32.private;
|
||||
output r46 as u32.private;
|
||||
output r28 as u32.private;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "bubblesort.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1 +0,0 @@
|
||||
13u32 2u32 4u32 3u32 5u32 10u32 7u32 1u32
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "bubblesort.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,287 +0,0 @@
|
||||
program bubblesort.aleo {
|
||||
// Executes the bubble sorting algorithm.
|
||||
// The original algorithm is given below.
|
||||
//
|
||||
// for i in 0..7 {
|
||||
// for j in 0..7-i {
|
||||
// // Move the smaller elements forward
|
||||
// if arr[j+1] < arr[j] {
|
||||
// // Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
// let swap = arr[j];
|
||||
// arr[j] = arr[j+1];
|
||||
// arr[j+1] = swap;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Note that the implementation below uses tuples instead of arrays.
|
||||
// The implementation also manually unrolls the loop.
|
||||
|
||||
transition bubble_sort(
|
||||
arr0: u32,
|
||||
arr1: u32,
|
||||
arr2: u32,
|
||||
arr3: u32,
|
||||
arr4: u32,
|
||||
arr5: u32,
|
||||
arr6: u32,
|
||||
arr7: u32,
|
||||
) -> (u32, u32, u32, u32, u32, u32, u32, u32) {
|
||||
|
||||
// Unroll the loops.
|
||||
|
||||
// (i, j) = (0, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (0, 1).
|
||||
// Move the smaller elements forward.
|
||||
if arr2 < arr1 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr1;
|
||||
arr1 = arr2;
|
||||
arr2 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (0, 2).
|
||||
// Move the smaller elements forward.
|
||||
if arr3 < arr2 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr2;
|
||||
arr2 = arr3;
|
||||
arr3 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (0, 3).
|
||||
// Move the smaller elements forward.
|
||||
if arr4 < arr3 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr3;
|
||||
arr3 = arr4;
|
||||
arr4 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (0, 4).
|
||||
// Move the smaller elements forward.
|
||||
if arr5 < arr4 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr4;
|
||||
arr4 = arr5;
|
||||
arr5 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (0, 5).
|
||||
// Move the smaller elements forward.
|
||||
if arr6 < arr5 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr5;
|
||||
arr5 = arr6;
|
||||
arr6 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (0, 6).
|
||||
// Move the smaller elements forward.
|
||||
if arr7 < arr6 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr6;
|
||||
arr6 = arr7;
|
||||
arr7 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (1, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (1, 1).
|
||||
// Move the smaller elements forward.
|
||||
if arr2 < arr1 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr1;
|
||||
arr1 = arr2;
|
||||
arr2 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (1, 2).
|
||||
// Move the smaller elements forward.
|
||||
if arr3 < arr2 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr2;
|
||||
arr2 = arr3;
|
||||
arr3 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (1, 3).
|
||||
// Move the smaller elements forward.
|
||||
if arr4 < arr3 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr3;
|
||||
arr3 = arr4;
|
||||
arr4 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (1, 4).
|
||||
// Move the smaller elements forward.
|
||||
if arr5 < arr4 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr4;
|
||||
arr4 = arr5;
|
||||
arr5 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (1, 5).
|
||||
// Move the smaller elements forward.
|
||||
if arr6 < arr5 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr5;
|
||||
arr5 = arr6;
|
||||
arr6 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (2, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (2, 1).
|
||||
// Move the smaller elements forward.
|
||||
if arr2 < arr1 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr1;
|
||||
arr1 = arr2;
|
||||
arr2 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (2, 2).
|
||||
// Move the smaller elements forward.
|
||||
if arr3 < arr2 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr2;
|
||||
arr2 = arr3;
|
||||
arr3 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (2, 3).
|
||||
// Move the smaller elements forward.
|
||||
if arr4 < arr3 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr3;
|
||||
arr3 = arr4;
|
||||
arr4 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (2, 4).
|
||||
// Move the smaller elements forward.
|
||||
if arr5 < arr4 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr4;
|
||||
arr4 = arr5;
|
||||
arr5 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (3, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (3, 1).
|
||||
// Move the smaller elements forward.
|
||||
if arr2 < arr1 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr1;
|
||||
arr1 = arr2;
|
||||
arr2 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (3, 2).
|
||||
// Move the smaller elements forward.
|
||||
if arr3 < arr2 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr2;
|
||||
arr2 = arr3;
|
||||
arr3 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (3, 3).
|
||||
// Move the smaller elements forward.
|
||||
if arr4 < arr3 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr3;
|
||||
arr3 = arr4;
|
||||
arr4 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (4, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (4, 1).
|
||||
// Move the smaller elements forward.
|
||||
if arr2 < arr1 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr1;
|
||||
arr1 = arr2;
|
||||
arr2 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (4, 2).
|
||||
// Move the smaller elements forward.
|
||||
if arr3 < arr2 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr2;
|
||||
arr2 = arr3;
|
||||
arr3 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (5, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (5, 1).
|
||||
// Move the smaller elements forward.
|
||||
if arr2 < arr1 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr1;
|
||||
arr1 = arr2;
|
||||
arr2 = temp;
|
||||
}
|
||||
|
||||
// (i, j) = (6, 0).
|
||||
// Move the smaller elements forward.
|
||||
if arr1 < arr0 {
|
||||
// Swap the elements at indexes ‘j‘ and ‘j+1‘
|
||||
let temp: u32 = arr0;
|
||||
arr0 = arr1;
|
||||
arr1 = temp;
|
||||
}
|
||||
|
||||
return (arr0, arr1, arr2, arr3, arr4, arr5, arr6, arr7);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
4
examples/core/.gitignore
vendored
4
examples/core/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,15 +0,0 @@
|
||||
# Leo core functions
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run this program, run:
|
||||
```bash
|
||||
leo run main <inputs>
|
||||
```
|
||||
|
||||
## Execute Guide
|
||||
|
||||
To execute this program, run:
|
||||
```bash
|
||||
leo execute main <inputs>
|
||||
```
|
@ -1,10 +0,0 @@
|
||||
program core.aleo;
|
||||
|
||||
|
||||
|
||||
function main:
|
||||
input r0 as field.private;
|
||||
hash.bhp256 r0 into r1 as field;
|
||||
hash.psd2 r1 into r2 as field;
|
||||
commit.bhp256 r2 1scalar into r3 as field;
|
||||
output r3 as field.private;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "core.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
1field
|
||||
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "core.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
program core.aleo {
|
||||
// This function takes as input a field `a` and calls several core functions.
|
||||
// Core functions are built-in to the Leo language and call handwritten, optimized circuits in the AVM.
|
||||
// To call a core function, use the correct capitalized identifier followed by two colons
|
||||
// and then the function name. Example: `Pedersen64::hash_to_field()`.
|
||||
transition main(a: field) -> field {
|
||||
let b: field = BHP256::hash_to_field(a);
|
||||
let c: field = Poseidon2::hash_to_field(b);
|
||||
let d: field = BHP256::commit_to_field(c, 1scalar);
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
4
examples/fibonacci/.gitignore
vendored
4
examples/fibonacci/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,20 +0,0 @@
|
||||
# fibonacci.aleo
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run this program, run:
|
||||
```bash
|
||||
leo run fibonacci <inputs>
|
||||
```
|
||||
|
||||
## Execute Guide
|
||||
|
||||
To execute this program, run:
|
||||
```bash
|
||||
leo execute fibonacci <inputs>
|
||||
```
|
||||
|
||||
## Overview
|
||||
This example shows how to calculate Fibonacci number using the [fast-doubling method](https://math.stackexchange.com/questions/1124590/need-help-understanding-fibonacci-fast-doubling-proof).
|
||||
|
||||
It takes the input data from `inputs/fibonacci.in`
|
@ -1 +0,0 @@
|
||||
63u8
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "fibonacci.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
program fibonacci.aleo {
|
||||
// This calculates the n-th fibonacci number (up to 64th)
|
||||
transition fibonacci(public n: u8) -> u128 {
|
||||
assert(n <= 64u8);
|
||||
|
||||
let f0: u128 = 0u128;
|
||||
let f1: u128 = 1u128;
|
||||
let c: u8 = 0u8;
|
||||
|
||||
let z: u8 = reverse_bits(n);
|
||||
|
||||
for i:u8 in 0u8..8u8 {
|
||||
if n > 0u8 {
|
||||
let f2i1: u128 = f1 * f1 + f0 * f0;
|
||||
let f2i: u128 = f0 * (2u128 * f1 - f0);
|
||||
if z & 1u8.shl(c) == 0u8 {
|
||||
f0 = f2i;
|
||||
f1 = f2i1;
|
||||
} else {
|
||||
f0 = f2i1;
|
||||
f1 = f2i + f2i1;
|
||||
}
|
||||
c = c + 1u8;
|
||||
n = n >> 1u8;
|
||||
}
|
||||
}
|
||||
|
||||
return f0;
|
||||
}
|
||||
|
||||
function reverse_bits(n: u8) -> u8 {
|
||||
let reverse: u8 = 0u8;
|
||||
|
||||
for i:u8 in 0u8..8u8 {
|
||||
if n > 0u8 {
|
||||
reverse = reverse << 1u8;
|
||||
|
||||
if n & 1u8 == 1u8 {
|
||||
reverse ^= 1u8;
|
||||
}
|
||||
|
||||
n = n >> 1u8;
|
||||
}
|
||||
}
|
||||
|
||||
return reverse;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
4
examples/groups/.gitignore
vendored
4
examples/groups/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,38 +0,0 @@
|
||||
# Leo group operations.
|
||||
|
||||
## Run Guide
|
||||
|
||||
To run this program, run:
|
||||
```bash
|
||||
leo run main <inputs>
|
||||
```
|
||||
|
||||
## Execute Guide
|
||||
|
||||
To execute this program, run:
|
||||
```bash
|
||||
leo execute main <inputs>
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
This example shows how to do basic operations over groups.
|
||||
|
||||
It takes the input data from inputs/groups.in
|
||||
|
||||
|
||||
## Documentation Group Element
|
||||
|
||||
The set of affine points on the elliptic curve passed into the Leo compiler forms a group.
|
||||
A subset of those points, defined by a chosen generator point, forms a subgroup of the group.
|
||||
Leo supports the set of points in this subgroup as a primitive data type.
|
||||
Group elements are special since their values can be defined as coordinate pairs ```(x, y)group```.
|
||||
The `group` type keyword group must be used when specifying a pair of group coordinates since implicit syntax would collide with normal tuple `(a, b)` values.
|
||||
|
||||
```
|
||||
let a = 0group; // the zero of the group
|
||||
|
||||
let b = group::GEN; // the group generator
|
||||
|
||||
let c = (0, 1)group; // coordinate notation
|
||||
```
|
@ -1,12 +0,0 @@
|
||||
program groups.aleo;
|
||||
|
||||
|
||||
|
||||
function main:
|
||||
input r0 as group.private;
|
||||
double r0 into r1;
|
||||
neg r1 into r2;
|
||||
mul r0 2scalar into r3;
|
||||
add r3 r2 into r4;
|
||||
add r4 group::GEN into r5;
|
||||
output r5 as group.private;
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "groups.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1 +0,0 @@
|
||||
1817767092074430972953743941103352519057913259183777531581123188265134806220group
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "groups.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
program groups.aleo {
|
||||
// This function takes a group coordinate as input `a` and performs several operations which should output the `0group`.
|
||||
// Note that the operations can be called as associated functions on the `a` variable.
|
||||
|
||||
transition main(a: group) -> group {
|
||||
// unary
|
||||
let b: group = a.double(); // 2a
|
||||
let c: group = b.neg(); // -2a
|
||||
|
||||
// binary
|
||||
let d: group = (a * 2scalar).add(c);
|
||||
|
||||
// generator
|
||||
let e: group = group::GEN;
|
||||
|
||||
return d + e;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Hacker's Delight
|
||||
|
||||
This directory contains a number of algorithms for counting trailing zeros as described in "Hacker's Delight, 2nd edition" by Henry S. Warren.
|
@ -1,3 +0,0 @@
|
||||
NETWORK=testnet
|
||||
PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
|
||||
ENDPOINT=http://localhost:3030
|
@ -1,4 +0,0 @@
|
||||
outputs/
|
||||
*.avm
|
||||
*.prover
|
||||
*.verifier
|
@ -1,36 +0,0 @@
|
||||
# src/ntzdebruijn.leo
|
||||
|
||||
## Build Guide
|
||||
|
||||
To compile and run this Leo program, run:
|
||||
```bash
|
||||
leo run <function-name> <inputs>
|
||||
```
|
||||
|
||||
## The Algorithm
|
||||
|
||||
This algorithm is detailed in "Hacker's Delight, 2nd edition"
|
||||
by Henry S. Warren, section 5-4, figure 5-26. Here is a summary.
|
||||
|
||||
After handling the all-zeros case,
|
||||
we isolate the rightmost `1` bit in the 32-bit input by
|
||||
using the C idiom `x & (-x)`. In Leo, the `-x` is
|
||||
written as `0u32.sub_wrapped(x)`.
|
||||
|
||||
A constant was discovered with the property that when it was multiplied
|
||||
by 1, 2, 4, ... 2**31, the 32 values all had different high 5-bit patterns.
|
||||
This constant is `0x04D7651F`.
|
||||
|
||||
In the algorithm, the 5 high bits are used as an index into the table
|
||||
`{0, 1, 2, 24, 3, 19, ...}`. The table's values were chosen so that
|
||||
they gave the correct number of trailing zeros for the inputs.
|
||||
|
||||
For example, if the isolated bit has 4 trailing zeros, the number is 2**4.
|
||||
The high 5 bits of `2**4 * 0x04D7651F` are `01001` which is 9. The table
|
||||
value at index 9 is therefore 4.
|
||||
|
||||
This algorithm was proposed by Danny Dubé in the comp.compression.research newsgroup:
|
||||
https://groups.google.com/g/comp.compression.research/c/x0NaZ3CJ6O4/m/PfGuchA7o60J
|
||||
|
||||
A description of de Bruijn cycles and their use for bit indexing can be seen
|
||||
here: http://supertech.csail.mit.edu/papers/debruijn.pdf
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "ntzdebruijn.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
@ -1 +0,0 @@
|
||||
2147483648u32
|
@ -1 +0,0 @@
|
||||
package = []
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"program": "ntzdebruijn.aleo",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"license": "MIT"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user