[Ceres]: Add bitwise ops, Address.to_bytes and Crypto.poseidon
This commit is contained in:
parent
5c3b42aff1
commit
f60f9122ba
10
CHANGELOG.md
10
CHANGELOG.md
@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [CERES 8.0.0]
|
||||
### Added
|
||||
- Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`.
|
||||
- `Int.mulmod` - combined builtin operation for multiplication and modulus.
|
||||
- `Crypto.poseidon` - a ZK/SNARK-friendly hash function (over the BLS12-381 scalar field).
|
||||
- `Address.to_bytes` - convert an address to its binary representation (for hashing, etc.).
|
||||
### Changed
|
||||
### Removed
|
||||
- `Bitwise.aes` standard library is removed - the builtin operations are superior.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
### Changed
|
||||
|
@ -632,6 +632,14 @@ All operations are *safe* with respect to overflow and underflow.
|
||||
The division and modulo operations throw an arithmetic error if the
|
||||
right-hand operand is zero.
|
||||
|
||||
Sophia arbitrary-sized integers (FATE) also supports the following bitwise operations:
|
||||
- bitwise and (`x band y`)
|
||||
- bitwise or (`x bor y`)
|
||||
- bitwise xor (`x bxor y`)
|
||||
- bitwise not (`bnot x`)
|
||||
- arithmetic bitshift left (`x << n`)
|
||||
- arithmetic bitshift right (`x >> n`)
|
||||
|
||||
## Bit fields
|
||||
|
||||
Sophia integers do not support bit arithmetic. Instead there is a separate
|
||||
|
@ -381,6 +381,12 @@ Call.gas_price : int
|
||||
|
||||
The gas price of the current call.
|
||||
|
||||
#### mulmod
|
||||
```
|
||||
Int.mulmod : (a : int, b : int, q : int) : int
|
||||
```
|
||||
|
||||
Combined multiplication and modulus, returns `(a * b) mod q`.
|
||||
|
||||
#### fee
|
||||
```
|
||||
@ -469,6 +475,13 @@ Chain.block_height : int"
|
||||
|
||||
The height of the current block (i.e. the block in which the current call will be included).
|
||||
|
||||
#### to_bytes
|
||||
```
|
||||
Address.to_bytes(a : address) : bytes(32)
|
||||
```
|
||||
|
||||
The binary representation of the address.
|
||||
|
||||
|
||||
##### bytecode_hash
|
||||
```
|
||||
@ -506,6 +519,13 @@ charging the calling contract. Note that this won't be visible in `Call.value`
|
||||
in the `init` call of the new contract. It will be included in
|
||||
`Contract.balance`, however.
|
||||
|
||||
#### poseidon
|
||||
```
|
||||
Crypto.poseidon(x1 : int, x2 : int) : int
|
||||
```
|
||||
|
||||
Hash two integers (in the scalar field of BLS12-381) to another integer (in the scalar
|
||||
field of BLS12-281). This is a ZK/SNARK-friendly hash function.
|
||||
|
||||
The type `'c` must be instantiated with a contract.
|
||||
|
||||
@ -926,90 +946,6 @@ It returns `true` iff the oracle query exist and has the expected type.
|
||||
These need to be explicitly included (with `.aes` suffix)
|
||||
|
||||
|
||||
### Bitwise
|
||||
|
||||
Bitwise operations on arbitrary precision integers.
|
||||
|
||||
#### bsr
|
||||
```
|
||||
Bitwise.bsr(n : int, x : int) : int
|
||||
```
|
||||
|
||||
Logical bit shift `x` right `n` positions.
|
||||
|
||||
|
||||
#### bsl
|
||||
```
|
||||
Bitwise.bsl(n : int, x : int) : int
|
||||
```
|
||||
|
||||
Logical bit shift `x` left `n` positions.
|
||||
|
||||
|
||||
#### bsli
|
||||
```
|
||||
Bitwise.bsli(n : int, x : int, lim : int) : int
|
||||
```
|
||||
|
||||
Logical bit shift `x` left `n` positions, limit to `lim` bits.
|
||||
|
||||
|
||||
#### band
|
||||
```
|
||||
Bitwise.band(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `and` of `x` and `y`.
|
||||
|
||||
|
||||
#### bor
|
||||
```
|
||||
Bitwise.bor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `or` of `x` and `y`.
|
||||
|
||||
|
||||
#### bxor
|
||||
```
|
||||
Bitwise.bxor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `xor` of `x` and `y`.
|
||||
|
||||
|
||||
#### bnot
|
||||
```
|
||||
Bitwise.bnot(x : int) : int
|
||||
```
|
||||
|
||||
Bitwise `not` of `x`. Defined and implemented as `bnot(x) = bxor(x, -1)`.
|
||||
|
||||
|
||||
#### uband
|
||||
```
|
||||
Bitwise.uband(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `and` of _non-negative_ numbers `x` and `y`.
|
||||
|
||||
|
||||
#### ubor
|
||||
```
|
||||
Bitwise.ubor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `or` of _non-negative_ `x` and `y`.
|
||||
|
||||
|
||||
#### ubxor
|
||||
```
|
||||
Bitwise.ubxor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `xor` of _non-negative_ `x` and `y`.
|
||||
|
||||
|
||||
### BLS12\_381
|
||||
|
||||
#### Types
|
||||
|
@ -256,8 +256,8 @@ Path ::= Id // Record field
|
||||
|
||||
BinOp ::= '||' | '&&' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||
| '::' | '++' | '+' | '-' | '*' | '/' | 'mod' | '^'
|
||||
| '|>'
|
||||
UnOp ::= '-' | '!'
|
||||
| 'band' | 'bor' | 'bxor' | '<<' | '>>' | '|>'
|
||||
UnOp ::= '-' | '!' | 'bnot'
|
||||
```
|
||||
|
||||
## Operators types
|
||||
@ -266,6 +266,7 @@ UnOp ::= '-' | '!'
|
||||
| --- | ---
|
||||
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
||||
| `!` `&&` `||` | logical operators
|
||||
| `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators
|
||||
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
||||
| `::` `++` | list operators
|
||||
| `|>` | functional operators
|
||||
@ -276,13 +277,17 @@ In order of highest to lowest precedence.
|
||||
|
||||
| Operators | Associativity
|
||||
| --- | ---
|
||||
| `!` | right
|
||||
| `!` `bnot`| right
|
||||
| `^` | left
|
||||
| `*` `/` `mod` | left
|
||||
| `-` (unary) | right
|
||||
| `+` `-` | left
|
||||
| `<<` `>>` | left
|
||||
| `::` `++` | right
|
||||
| `<` `>` `=<` `>=` `==` `!=` | none
|
||||
| `band` | left
|
||||
| `bxor` | left
|
||||
| `bor` | left
|
||||
| `&&` | right
|
||||
| `||` | right
|
||||
| `|>` | left
|
||||
|
@ -1,126 +0,0 @@
|
||||
@compiler >= 4.3
|
||||
|
||||
namespace Bitwise =
|
||||
|
||||
// bit shift 'x' right 'n' postions
|
||||
function bsr(n : int, x : int) : int =
|
||||
let step = 2^n
|
||||
let res = x / step
|
||||
if (x >= 0 || x mod step == 0)
|
||||
res
|
||||
else
|
||||
res - 1
|
||||
|
||||
// bit shift 'x' left 'n' positions
|
||||
function bsl(n : int, x : int) : int =
|
||||
x * 2^n
|
||||
|
||||
// bit shift 'x' left 'n' positions, limit at 'lim' bits
|
||||
function bsli(n : int, x : int, lim : int) : int =
|
||||
(x * 2^n) mod (2^lim)
|
||||
|
||||
// bitwise 'and' for arbitrary precision integers
|
||||
function band(a : int, b : int) : int =
|
||||
if (a >= 0 && b >= 0)
|
||||
uband_(a, b)
|
||||
elif (b >= 0)
|
||||
ubnand_(b, -1 - a)
|
||||
elif (a >= 0)
|
||||
ubnand_(a, -1 - b)
|
||||
else
|
||||
-1 - ubor_(-1 - a, -1 - b)
|
||||
|
||||
// bitwise 'or' for arbitrary precision integers
|
||||
function
|
||||
bor : (int, int) => int
|
||||
bor(0, b) = b
|
||||
bor(a, 0) = a
|
||||
bor(a : int, b : int) : int =
|
||||
if (a >= 0 && b >= 0)
|
||||
ubor_(a, b)
|
||||
elif (b >= 0)
|
||||
-1 - ubnand_(-1 - a, b)
|
||||
elif (a >= 0)
|
||||
-1 - ubnand_(-1 - b, a)
|
||||
else
|
||||
-1 - uband_(-1 - a, -1 - b)
|
||||
|
||||
// bitwise 'xor' for arbitrary precision integers
|
||||
function
|
||||
bxor : (int, int) => int
|
||||
bxor(0, b) = b
|
||||
bxor(a, 0) = a
|
||||
bxor(a, b) =
|
||||
if (a >= 0 && b >= 0)
|
||||
ubxor_(a, b)
|
||||
elif (b >= 0)
|
||||
-1 - ubxor_(-1 - a, b)
|
||||
elif (a >= 0)
|
||||
-1 - ubxor_(a, -1 - b)
|
||||
else
|
||||
ubxor_(-1 - a, -1 - b)
|
||||
|
||||
// bitwise 'not' for arbitrary precision integers
|
||||
function bnot(a : int) = bxor(a, -1)
|
||||
|
||||
// Bitwise 'and' for non-negative integers
|
||||
function uband(a : int, b : int) : int =
|
||||
require(a >= 0 && b >= 0, "uband is only defined for non-negative integers")
|
||||
switch((a, b))
|
||||
(0, _) => 0
|
||||
(_, 0) => 0
|
||||
_ => uband__(a, b, 1, 0)
|
||||
|
||||
private function uband_(a, b) = uband__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
uband__(0, b, val, acc) = acc
|
||||
uband__(a, 0, val, acc) = acc
|
||||
uband__(a, b, val, acc) =
|
||||
switch (a mod 2 + b mod 2)
|
||||
2 => uband__(a / 2, b / 2, val * 2, acc + val)
|
||||
_ => uband__(a / 2, b / 2, val * 2, acc)
|
||||
|
||||
// Bitwise 'or' for non-negative integers
|
||||
function ubor(a, b) =
|
||||
require(a >= 0 && b >= 0, "ubor is only defined for non-negative integers")
|
||||
switch((a, b))
|
||||
(0, _) => b
|
||||
(_, 0) => a
|
||||
_ => ubor__(a, b, 1, 0)
|
||||
|
||||
private function ubor_(a, b) = ubor__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
ubor__(0, 0, val, acc) = acc
|
||||
ubor__(a, b, val, acc) =
|
||||
switch (a mod 2 + b mod 2)
|
||||
0 => ubor__(a / 2, b / 2, val * 2, acc)
|
||||
_ => ubor__(a / 2, b / 2, val * 2, acc + val)
|
||||
|
||||
//Bitwise 'xor' for non-negative integers
|
||||
function
|
||||
ubxor : (int, int) => int
|
||||
ubxor(0, b) = b
|
||||
ubxor(a, 0) = a
|
||||
ubxor(a, b) =
|
||||
require(a >= 0 && b >= 0, "ubxor is only defined for non-negative integers")
|
||||
ubxor__(a, b, 1, 0)
|
||||
|
||||
private function ubxor_(a, b) = ubxor__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
ubxor__(0, 0, val, acc) = acc
|
||||
ubxor__(a, b, val, acc) =
|
||||
switch(a mod 2 + b mod 2)
|
||||
1 => ubxor__(a / 2, b / 2, val * 2, acc + val)
|
||||
_ => ubxor__(a / 2, b / 2, val * 2, acc)
|
||||
|
||||
private function ubnand_(a, b) = ubnand__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
ubnand__(0, b, val, acc) = acc
|
||||
ubnand__(a, b, val, acc) =
|
||||
switch((a mod 2, b mod 2))
|
||||
(1, 0) => ubnand__(a / 2, b / 2, val * 2, acc + val)
|
||||
_ => ubnand__(a / 2, b / 2, val * 2, acc)
|
@ -764,7 +764,8 @@ global_env() ->
|
||||
{"ecrecover_secp256k1", Fun([Hash, Bytes(65)], Option(Bytes(20)))},
|
||||
{"sha3", Fun1(A, Hash)},
|
||||
{"sha256", Fun1(A, Hash)},
|
||||
{"blake2b", Fun1(A, Hash)}]) },
|
||||
{"blake2b", Fun1(A, Hash)},
|
||||
{"poseidon", Fun([Int, Int], Int)}]) },
|
||||
|
||||
%% Fancy BLS12-381 crypto operations
|
||||
MCL_BLS12_381_Scope = #scope
|
||||
@ -849,14 +850,16 @@ global_env() ->
|
||||
]) },
|
||||
|
||||
%% Conversion
|
||||
IntScope = #scope{ funs = MkDefs([{"to_str", Fun1(Int, String)}]) },
|
||||
IntScope = #scope{ funs = MkDefs([{"to_str", Fun1(Int, String)},
|
||||
{"mulmod", Fun([Int, Int, Int], Int)}]) },
|
||||
|
||||
AddressScope = #scope{ funs = MkDefs([{"to_str", Fun1(Address, String)},
|
||||
{"to_bytes", Fun1(Address, Bytes(32))},
|
||||
{"to_contract", FunC(address_to_contract, [Address], A)},
|
||||
{"is_oracle", Fun1(Address, Bool)},
|
||||
{"is_contract", Fun1(Address, Bool)},
|
||||
{"is_payable", Fun1(Address, Bool)}]) },
|
||||
|
||||
|
||||
#env{ scopes =
|
||||
#{ [] => TopScope
|
||||
, ["Chain"] => ChainScope
|
||||
@ -2396,6 +2399,11 @@ infer_infix({IntOp, As})
|
||||
IntOp == '^'; IntOp == 'mod' ->
|
||||
Int = {id, As, "int"},
|
||||
{fun_t, As, [], [Int, Int], Int};
|
||||
infer_infix({BitOp, As})
|
||||
when BitOp == 'band'; BitOp == 'bor'; BitOp == 'bxor';
|
||||
BitOp == '<<'; BitOp == '>>' ->
|
||||
Int = {id, As, "int"},
|
||||
{fun_t, As, [], [Int, Int], Int};
|
||||
infer_infix({RelOp, As})
|
||||
when RelOp == '=='; RelOp == '!=';
|
||||
RelOp == '<'; RelOp == '>';
|
||||
@ -2423,6 +2431,9 @@ infer_infix({'|>', As}) ->
|
||||
infer_prefix({'!',As}) ->
|
||||
Bool = {id, As, "bool"},
|
||||
{fun_t, As, [], [Bool], Bool};
|
||||
infer_prefix({BitOp,As}) when BitOp =:= 'bnot' ->
|
||||
Int = {id, As, "int"},
|
||||
{fun_t, As, [], [Int], Int};
|
||||
infer_prefix({IntOp,As}) when IntOp =:= '-' ->
|
||||
Int = {id, As, "int"},
|
||||
{fun_t, As, [], [Int], Int}.
|
||||
|
@ -32,12 +32,13 @@
|
||||
|
||||
-type op() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' |
|
||||
'<' | '>' | '=<' | '>=' | '==' | '!=' | '!' |
|
||||
'band' | 'bor' | 'bxor' | 'bnot' | '<<' | '>>' |
|
||||
map_get | map_get_d | map_set | map_from_list | map_to_list |
|
||||
map_delete | map_member | map_size | string_length |
|
||||
string_concat | bits_set | bits_clear | bits_test | bits_sum |
|
||||
bits_intersection | bits_union | bits_difference |
|
||||
contract_to_address | address_to_contract | crypto_verify_sig | crypto_verify_sig_secp256k1 |
|
||||
crypto_sha3 | crypto_sha256 | crypto_blake2b |
|
||||
crypto_sha3 | crypto_sha256 | crypto_blake2b | crypto_poseidon |
|
||||
crypto_ecverify_secp256k1 | crypto_ecrecover_secp256k1 |
|
||||
mcl_bls12_381_g1_neg | mcl_bls12_381_g1_norm | mcl_bls12_381_g1_valid |
|
||||
mcl_bls12_381_g1_is_zero | mcl_bls12_381_g1_add | mcl_bls12_381_g1_mul |
|
||||
@ -278,7 +279,7 @@ builtins() ->
|
||||
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
|
||||
{["Crypto"], [{"verify_sig", 3}, {"verify_sig_secp256k1", 3},
|
||||
{"ecverify_secp256k1", 3}, {"ecrecover_secp256k1", 2},
|
||||
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}, {"poseidon", 2}]},
|
||||
{["MCL_BLS12_381"], [{"g1_neg", 1}, {"g1_norm", 1}, {"g1_valid", 1}, {"g1_is_zero", 1}, {"g1_add", 2}, {"g1_mul", 2},
|
||||
{"g2_neg", 1}, {"g2_norm", 1}, {"g2_valid", 1}, {"g2_is_zero", 1}, {"g2_add", 2}, {"g2_mul", 2},
|
||||
{"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 1},
|
||||
@ -291,8 +292,9 @@ builtins() ->
|
||||
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
||||
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
||||
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
||||
{["Int"], [{"to_str", 1}]},
|
||||
{["Address"], [{"to_str", 1}, {"to_contract", 1}, {"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
||||
{["Int"], [{"to_str", 1}, {"mulmod", 2}]},
|
||||
{["Address"], [{"to_str", 1}, {"to_bytes", 1}, {"to_contract", 1},
|
||||
{"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
||||
],
|
||||
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|
||||
|| {NS, Funs} <- Scopes,
|
||||
@ -748,8 +750,9 @@ expr_to_fcode(Env, Type, {app, Ann, {Op, _}, [A, B]}) when is_atom(Op) ->
|
||||
expr_to_fcode(Env, _Type, {app, Ann, {Op, _}, [A]}) when is_atom(Op) ->
|
||||
FAnn = to_fann(Ann),
|
||||
case Op of
|
||||
'-' -> {op, FAnn, '-', [{lit, FAnn, {int, 0}}, expr_to_fcode(Env, A)]};
|
||||
'!' -> {op, FAnn, '!', [expr_to_fcode(Env, A)]}
|
||||
'-' -> {op, FAnn, '-', [{lit, FAnn, {int, 0}}, expr_to_fcode(Env, A)]};
|
||||
'bnot' -> {op, FAnn, 'bnot', [expr_to_fcode(Env, A)]};
|
||||
'!' -> {op, FAnn, '!', [expr_to_fcode(Env, A)]}
|
||||
end;
|
||||
|
||||
%% Function calls
|
||||
@ -1170,9 +1173,9 @@ op_builtins() ->
|
||||
stringinternal_sha3, stringinternal_sha256, stringinternal_blake2b,
|
||||
char_to_int, char_from_int, stringinternal_to_lower, stringinternal_to_upper,
|
||||
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
||||
bits_difference, int_to_str, address_to_str, crypto_verify_sig,
|
||||
bits_difference, int_to_str, int_mulmod, address_to_str, address_to_bytes, crypto_verify_sig,
|
||||
address_to_contract,
|
||||
crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b,
|
||||
crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b, crypto_poseidon,
|
||||
crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1,
|
||||
mcl_bls12_381_g1_neg, mcl_bls12_381_g1_norm, mcl_bls12_381_g1_valid,
|
||||
mcl_bls12_381_g1_is_zero, mcl_bls12_381_g1_add, mcl_bls12_381_g1_mul,
|
||||
|
@ -667,6 +667,12 @@ op_to_scode('>=') -> aeb_fate_ops:egt(?a, ?a, ?a);
|
||||
op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a);
|
||||
op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a);
|
||||
op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a);
|
||||
op_to_scode('bnot') -> aeb_fate_ops:bin_not(?a, ?a);
|
||||
op_to_scode('band') -> aeb_fate_ops:bin_and(?a, ?a, ?a);
|
||||
op_to_scode('bor') -> aeb_fate_ops:bin_or(?a, ?a, ?a);
|
||||
op_to_scode('bxor') -> aeb_fate_ops:bin_xor(?a, ?a, ?a);
|
||||
op_to_scode('<<') -> aeb_fate_ops:bin_sl(?a, ?a, ?a);
|
||||
op_to_scode('>>') -> aeb_fate_ops:bin_sr(?a, ?a, ?a);
|
||||
op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a);
|
||||
op_to_scode(map_get_d) -> aeb_fate_ops:map_lookup(?a, ?a, ?a, ?a);
|
||||
op_to_scode(map_set) -> aeb_fate_ops:map_update(?a, ?a, ?a, ?a);
|
||||
@ -691,7 +697,9 @@ op_to_scode(bits_intersection) -> aeb_fate_ops:bits_and(?a, ?a, ?a);
|
||||
op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a);
|
||||
op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
||||
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
||||
op_to_scode(address_to_bytes) -> aeb_fate_ops:addr_to_bytes(?a, ?a);
|
||||
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
||||
op_to_scode(int_mulmod) -> aeb_fate_ops:mulmod(?a, ?a, ?a, ?a);
|
||||
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
||||
op_to_scode(address_to_contract) -> aeb_fate_ops:address_to_contract(?a, ?a);
|
||||
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
|
||||
@ -701,6 +709,7 @@ op_to_scode(crypto_ecrecover_secp256k1) -> aeb_fate_ops:ecrecover_secp256k1(?a,
|
||||
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||
op_to_scode(crypto_poseidon) -> aeb_fate_ops:poseidon(?a, ?a, ?a);
|
||||
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||
op_to_scode(stringinternal_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||
@ -973,6 +982,13 @@ attributes(I) ->
|
||||
{'DIV', A, B, C} -> Pure(A, [B, C]);
|
||||
{'MOD', A, B, C} -> Pure(A, [B, C]);
|
||||
{'POW', A, B, C} -> Pure(A, [B, C]);
|
||||
{'MULMOD', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'BAND', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BOR', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BXOR', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BNOT', A, B} -> Pure(A, [B]);
|
||||
{'BSL', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BSR', A, B, C} -> Pure(A, [B, C]);
|
||||
{'LT', A, B, C} -> Pure(A, [B, C]);
|
||||
{'GT', A, B, C} -> Pure(A, [B, C]);
|
||||
{'EQ', A, B, C} -> Pure(A, [B, C]);
|
||||
@ -1025,12 +1041,14 @@ attributes(I) ->
|
||||
{'SHA3', A, B} -> Pure(A, [B]);
|
||||
{'SHA256', A, B} -> Pure(A, [B]);
|
||||
{'BLAKE2B', A, B} -> Pure(A, [B]);
|
||||
{'POSEIDON', A, B, C} -> Pure(A, [B, C]);
|
||||
{'VERIFY_SIG', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'VERIFY_SIG_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
||||
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
||||
{'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]);
|
||||
{'ADDRESS_TO_BYTES', A, B} -> Pure(A, [B]);
|
||||
{'AUTH_TX_HASH', A} -> Pure(A, []);
|
||||
{'AUTH_TX', A} -> Pure(A, []);
|
||||
{'BYTES_TO_INT', A, B} -> Pure(A, [B]);
|
||||
|
@ -335,14 +335,19 @@ expr100() ->
|
||||
|
||||
expr150() -> infixl(expr200(), binop('|>')).
|
||||
expr200() -> infixr(expr300(), binop('||')).
|
||||
expr300() -> infixr(expr400(), binop('&&')).
|
||||
expr300() -> infixr(expr325(), binop('&&')).
|
||||
expr325() -> infixl(expr350(), binop('bor')).
|
||||
expr350() -> infixl(expr375(), binop('bxor')).
|
||||
expr375() -> infixl(expr400(), binop('band')).
|
||||
expr400() -> infix(expr500(), binop(['<', '>', '=<', '>=', '==', '!='])).
|
||||
expr500() -> infixr(expr600(), binop(['::', '++'])).
|
||||
expr500() -> infixr(expr550(), binop(['::', '++'])).
|
||||
expr550() -> infixl(expr600(), binop(['<<', '>>'])).
|
||||
expr600() -> infixl(expr650(), binop(['+', '-'])).
|
||||
expr650() -> ?RULE(many(token('-')), expr700(), prefixes(_1, _2)).
|
||||
expr700() -> infixl(expr750(), binop(['*', '/', mod])).
|
||||
expr750() -> infixl(expr800(), binop(['^'])).
|
||||
expr800() -> ?RULE(many(token('!')), expr900(), prefixes(_1, _2)).
|
||||
expr800() -> ?RULE(many(token('!')), expr850(), prefixes(_1, _2)).
|
||||
expr850() -> ?RULE(many(token('bnot')), expr900(), prefixes(_1, _2)).
|
||||
expr900() -> ?RULE(exprAtom(), many(elim()), elim(_1, _2)).
|
||||
|
||||
exprAtom() ->
|
||||
|
@ -436,15 +436,20 @@ bin_prec('=') -> { 0, 0, 0}; %% Always printed inside '[ ]'
|
||||
bin_prec('@') -> { 0, 0, 0}; %% Only in error messages
|
||||
bin_prec('|>') -> {150, 150, 200};
|
||||
bin_prec('||') -> {200, 300, 200};
|
||||
bin_prec('&&') -> {300, 400, 300};
|
||||
bin_prec('&&') -> {300, 325, 300};
|
||||
bin_prec('bor') -> {325, 350, 325};
|
||||
bin_prec('bxor') -> {350, 375, 350};
|
||||
bin_prec('band') -> {375, 400, 375};
|
||||
bin_prec('<') -> {400, 500, 500};
|
||||
bin_prec('>') -> {400, 500, 500};
|
||||
bin_prec('=<') -> {400, 500, 500};
|
||||
bin_prec('>=') -> {400, 500, 500};
|
||||
bin_prec('==') -> {400, 500, 500};
|
||||
bin_prec('!=') -> {400, 500, 500};
|
||||
bin_prec('++') -> {500, 600, 500};
|
||||
bin_prec('::') -> {500, 600, 500};
|
||||
bin_prec('++') -> {500, 550, 500};
|
||||
bin_prec('::') -> {500, 550, 500};
|
||||
bin_prec('<<') -> {550, 600, 550};
|
||||
bin_prec('>>') -> {550, 600, 550};
|
||||
bin_prec('+') -> {600, 600, 650};
|
||||
bin_prec('-') -> {600, 600, 650};
|
||||
bin_prec('*') -> {700, 700, 750};
|
||||
@ -454,7 +459,8 @@ bin_prec('^') -> {750, 750, 800}.
|
||||
|
||||
-spec un_prec(aeso_syntax:un_op()) -> {integer(), integer()}.
|
||||
un_prec('-') -> {650, 650};
|
||||
un_prec('!') -> {800, 800}.
|
||||
un_prec('!') -> {800, 800};
|
||||
un_prec('bnot') -> {850, 850}.
|
||||
|
||||
equals(Ann, A, B) ->
|
||||
{app, [{format, infix} | Ann], {'=', Ann}, [A, B]}.
|
||||
|
@ -45,7 +45,7 @@ lexer() ->
|
||||
|
||||
Keywords = ["contract", "include", "let", "switch", "type", "record", "datatype", "if", "elif", "else", "function",
|
||||
"stateful", "payable", "true", "false", "mod", "public", "entrypoint", "private", "indexed", "namespace",
|
||||
"interface", "main", "using", "as", "for", "hiding"
|
||||
"interface", "main", "using", "as", "for", "hiding", "band", "bor", "bxor", "bnot"
|
||||
],
|
||||
KW = string:join(Keywords, "|"),
|
||||
|
||||
|
@ -107,8 +107,8 @@
|
||||
|
||||
-type bin_op() :: '+' | '-' | '*' | '/' | mod | '^'
|
||||
| '++' | '::' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||
| '||' | '&&' | '..' | '|>'.
|
||||
-type un_op() :: '-' | '!'.
|
||||
| '||' | '&&' | '..' | 'band' | 'bor' | 'bxor' | '>>' | '<<' | '|>'.
|
||||
-type un_op() :: '-' | '!' | 'bnot'.
|
||||
|
||||
-type expr()
|
||||
:: {lam, ann(), [arg()], expr()}
|
||||
|
@ -225,6 +225,7 @@ compilable_contracts() ->
|
||||
"unapplied_named_arg_builtin",
|
||||
"resolve_field_constraint_by_arity",
|
||||
"toplevel_constants",
|
||||
"ceres",
|
||||
"test" % Custom general-purpose test file. Keep it last on the list.
|
||||
].
|
||||
|
||||
|
@ -53,7 +53,7 @@ simple_contracts_test_() ->
|
||||
%% associativity
|
||||
[ RightAssoc(Op) || Op <- ["||", "&&", "::", "++"] ],
|
||||
[ NonAssoc(Op) || Op <- ["==", "!=", "<", ">", "=<", ">="] ],
|
||||
[ LeftAssoc(Op) || Op <- ["+", "-", "*", "/", "mod"] ],
|
||||
[ LeftAssoc(Op) || Op <- ["+", "-", "*", "/", "mod", "band", "bor", "bxor", "<<", ">>"] ],
|
||||
|
||||
%% precedence
|
||||
[ Stronger(Op2, Op1) || [T1 , T2 | _] <- tails(Tiers), Op1 <- T1, Op2 <- T2 ],
|
||||
|
@ -39,7 +39,8 @@ all_tokens() ->
|
||||
%% Symbols
|
||||
lists:map(Lit, [',', '.', ';', '|', ':', '(', ')', '[', ']', '{', '}']) ++
|
||||
%% Operators
|
||||
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod, ':', '::', '->', '=>', '||', '&&', '!']) ++
|
||||
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod,
|
||||
':', '::', '->', '=>', '||', '&&', '!', 'band', 'bor', 'bxor', 'bnot' ,'<<', '>>']) ++
|
||||
%% Keywords
|
||||
lists:map(Lit, [contract, type, 'let', switch]) ++
|
||||
%% Comment token (not an actual token), just for tests
|
||||
|
14
test/contracts/ceres.aes
Normal file
14
test/contracts/ceres.aes
Normal file
@ -0,0 +1,14 @@
|
||||
contract C =
|
||||
entrypoint test() =
|
||||
let a : int = 23
|
||||
let b : int = 52
|
||||
let c = a bor b
|
||||
let d = c bxor b
|
||||
let e = d band b
|
||||
let f = bnot a
|
||||
let g = f << 2
|
||||
let h = g >> 2
|
||||
let i = Int.mulmod(a, b, h)
|
||||
let j = Crypto.poseidon(i, a)
|
||||
let k : bytes(32) = Address.to_bytes(Call.origin)
|
||||
(a bor b band c bxor a << bnot b >> a, k)
|
Loading…
x
Reference in New Issue
Block a user