Math
The Cairo common library has modules for some common operations.
The following are available:
- Not zero:
assert_not_zero(val)
. Asserts thatval
is not zero.
- Not equal:
assert_not_equal(a, b)
. Asserts thata
is not equal tob
.
- Not negative:
assert_nn(val)
. Asserts thatval
is not negative.
- Less than or equal to:
assert_le(a, b)
. Asserts thata
is less than or equal tob
.
- Less than:
assert_lt(a, b)
. Asserts thata
is less thanb
.
- Not negative and less than or equal to:
assert_nn_le()
. Asserts thata
is both not negative and less than or equal tob
.
- In range:
assert_in_range(val, a, b)
. Asserts thatval
is both greater than or equal toa
, and less thanb
.
- 250-bit:
assert_250_bit(val)
. Asserts thatval
is smaller then the maximum value in 250-bit space.
- Split felt:
split_felt(val)
. Returnshigh
andlow
parts ofval
.- See integer lifts.
- Less than or equal to (with split felt):
assert_le_felt(a, b)
. Asserts thata
is less than or equal tob
using split felt method.- See integer lifts
- Less than (with split felt):
assert_lt_felt(a, b)
. Asserts thata
is less thanb
using split felt method.- See integer lifts
- Absolute value:
abs_value(val)
. Returnsval
as a positive value.
- Sign:
sign(val)
. Returns one of-1
,0
or1
for aval
that is negative, zero or positive respectively.
- Unsigned division remainder:
unsigned_div_rem(value, div)
. Returns the quotientq
and remainderr
from integer division ofvalue/div
as positive values.
- Signed division remainder:
signed_div_rem(value, div)
. Returns the quotientq
and remainderr
from integer division ofvalue/div
, with quotient sign either positive or negative.- Handles integer and modulo operations with negative numbers the same way Python does, where
-100 // 3
returns-34
and-100 % 3
returns2
.
%lang starknet
%builtins pedersen range_check
from starkware.cairo.common.math import (
assert_not_zero, assert_not_equal, assert_nn, assert_le, assert_lt, assert_nn_le, assert_in_range, assert_250_bit, split_felt, assert_le_felt, assert_lt_felt, abs_value, sign, unsigned_div_rem, signed_div_rem)
# Accepts two numbers for integer division (signed, unsigned).
# Demonstrates successful cases of math operations.
@view
func check_values{range_check_ptr}(
num_1: felt, num_2: felt) -> (
u_quot: felt, u_rem: felt, s_quot: felt, s_rem: felt):
alloc_locals
assert_not_zero(100)
assert_not_zero(-100)
# assert_not_zero(0) # Fails.
assert_not_equal(100, 150)
# assert_not_equal(100, 100) # Fails.
assert_nn(100)
assert_nn(0)
# assert_nn(0) # Fails.
assert_le(100, 150)
assert_le(100, 100)
# assert_le(100, 50) # Fails.
assert_lt(100, 150)
# assert_lt(100, 100) # Fails.
# assert_lt(100, 150) # Fails.
assert_nn_le(100, 150)
# assert_nn_le(-100, 150) # Fails.
# assert_nn_le(100, 50) # Fails.
assert_in_range(150, 100, 200)
assert_in_range(150, -100, 200)
# assert_in_range(50, 100, 200) # Fails.
assert_250_bit(9234)
assert_250_bit(2**250 - 1)
# assert_250_bit(2**250) # Fails.
# assert_250_bit(-100) # Fails.
let (high_1, low_1) = split_felt(100 * 2**128 + 150)
assert high_1 = 100 # Just crosses mid-point (128 bits)
assert low_1 = 150
let (high_2, low_2) = split_felt(100 * 2**130 + 150)
assert high_2 = 100 * 2 ** 2 # A bit more than high_1
assert low_2 = 150
assert_le_felt(150, 200)
assert_le_felt(150, 150)
# assert_le_felt(150, 50) # Fails.
assert_lt_felt(150, 200)
# assert_lt_felt(150, 150) Fails.
# assert_lt_felt(150, 50) Fails.
let (local a) = abs_value(-150)
assert a = 150
let (local b) = sign(0)
assert b = 0
let (local c) = sign(-50)
assert c = -1
let (local d, e) = unsigned_div_rem(100, 3)
assert d = 33
assert e = 1
let (local u_quot, u_rem) = unsigned_div_rem(num_1, num_2)
# This check must be less than 2 ** 64
let RANGE_CHECK_BOUND = 2 ** 20
let (local f, g) = signed_div_rem(-100, 3, RANGE_CHECK_BOUND)
# To have these asserts pass, the -1 and +1 have been added to
# the expected values.
assert f = -34
assert g = 3
let (local s_quot, s_rem) = signed_div_rem(-num_1, num_2,
RANGE_CHECK_BOUND)
return (u_quot, u_rem, s_quot, s_rem)
end
Save as math.cairo
.
Compile
Then, to compile:
starknet-compile math.cairo \
--output math_compiled.json \
--abi math_contract_abi.json
Deploy
Then, to deploy:
starknet deploy --contract math_compiled.json \
--network=alpha
Returns:
Deploy transaction was sent.
Contract address: 0x069c755d08c37685d6a1705277c59567fe1f764d009354d8987ea49d134dcc73
Transaction ID: 169365
Note: Remove the zero after the x
, 0x[0]12345. E.g., 0x0123abc becomes 0x123abc.
Monitor
Check the status of the transaction:
starknet tx_status --network=alpha --id=169365
Returns:
{
"block_id": 38624
"tx_status": "PENDING"
}
Interact
Then, to interact supply a divisor and remainder (1000, 501):
starknet call \
--network=alpha \
--address 0x69c755d08c37685d6a1705277c59567fe1f764d009354d8987ea49d134dcc73 \
--abi math_contract_abi.json \
--function check_values \
--inputs 1000 501
Returns:
1 499 3618502788666131213697322783095070105623107215331596699973092056135872020479 2
Recall that the prime used for Cairo is:
>>> prime = 2**251 + 17 * 2**192 + 1`
>>> prime
3618502788666131213697322783095070105623107215331596699973092056135872020481
So the result (...0479
) is two less than the largest number (...0481
),
it is therefore equivalent to -2
.
So the result for signed_div_rem(-1000, 501) is (-2, 2), which matches the Python equivalent:
>>> -1000 // 501
-2
>>> -1000 % 501
2
Status options:
- NOT_RECEIVED: The transaction has not been received yet (i.e., not written to storage).
- RECEIVED: The transaction was received by the operator.
- PENDING: The transaction passed the validation and is waiting to be sent on-chain.
- REJECTED: The transaction failed validation and thus was skipped.
- ACCEPTED_ONCHAIN: The transaction was accepted on-chain.
- PENDING: The transaction passed the validation and is waiting to be sent on-chain.
Visit the voyager explorer to see the transactions.