Arithmetic Operations

An arithmetic expression is an expression that results in a TealType.uint64 value. In PyTeal, arithmetic expressions include integer and boolean operators (booleans are the integers 0 or 1). The table below summarized all arithmetic expressions in PyTeal.

Operator Overloaded Semantics Example
Lt(a, b) a < b 1 if a is less than b, 0 otherwise Int(1) < Int(5)
Gt(a, b) a > b 1 if a is greater than b, 0 otherwise Int(1) > Int(5)
Le(a, b) a <= b 1 if a is no greater than b, 0 otherwise Int(1) <= Int(5)
Ge(a, b) a >= b 1 if a is no less than b, 0 otherwise Int(1) >= Int(5)
Add(a, b) a + b a + b, error (panic) if overflow Int(1) + Int(5)
Minus(a, b) a - b a - b, error if underflow Int(5) - Int(1)
Mul(a, b) a * b a * b, error if overflow Int(2) * Int(3)
Div(a, b) a / b a / b, error if divided by zero Int(3) / Int(2)
Mod(a, b) a % b a % b, modulo operation Int(7) % Int(3)
Eq(a, b) a == b 1 if a equals b, 0 otherwise Int(7) == Int(7)
Neq(a, b) a != b 0 if a equals b, 1 otherwise Int(7) != Int(7)
And(a, b)   1 if a > 0 && b > 0, 0 otherwise And(Int(1), Int(1))
Or(a, b)   1 if a > 0 || b > 0, 0 otherwise Or(Int(1), Int(0))
Not(a)   1 if a equals 0, 0 otherwise Not(Int(0))
BitwiseAnd(a,b) a & b a & b, bitwise and operation Int(1) & Int(3)
BitwiseOr(a,b) a | b a | b, bitwise or operation Int(2) | Int(5)
BitwiseXor(a,b) a ^ b a ^ b, bitwise xor operation Int(3) ^ Int(7)
BitwiseNot(a) ~a ~a, bitwise complement operation ~Int(1)

Most of the above operations take two TealType.uint64 values as inputs. In addition, Eq(a, b) (==) and Neq(a, b) (!=) also work for byte slices. For example, Arg(0) == Arg(1) and Arg(0) != Arg(1) are valid PyTeal expressions.

Both And and Or also support more than 2 arguments when called as functions:

  • And(a, b, ...)
  • Or(a, b, ...)

The associativity and precedence of the overloaded Python arithmetic operators are the same as the original python operators . For example:

  • Int(1) + Int(2) + Int(3) is equivalent to Add(Add(Int(1), Int(2)), Int(3))
  • Int(1) + Int(2) * Int(3) is equivalent to Add(Int(1), Mul(Int(2), Int(3)))

Byteslice Arithmetic

Byteslice arithemetic is available for Teal V4 and above. Byteslice arithmetic operators allow up to 512-bit arithmetic. In PyTeal, byteslice arithmetic expressions include TealType.Bytes values as arguments (with the exception of BytesZero) and must be 64 bytes or less. The table below summarizes the byteslize arithmetic operations in PyTeal.

Operator Return Type Example Example Result
BytesLt(a, b) TealType.uint64 BytesLt(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0
BytesGt(a, b) TealType.uint64 BytesGt(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 1
BytesLe(a, b) TealType.uint64 BytesLe(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0
BytesGe(a, b) TealType.uint64 BytesGe(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 1
BytesEq(a, b) TealType.uint64 BytesEq(Bytes("base16", "0xFF"), Bytes("base16", "0xFF")) 1
BytesNeq(a, b) TealType.uint64 BytesNeq(Bytes("base16", "0xFF"), Bytes("base16", "0xFF")) 0
BytesAdd(a, b) TealType.Bytes BytesAdd(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0x01FD
BytesMinus(a, b) TealType.Bytes BytesMinus(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0x01
BytesMul(a, b) TealType.Bytes BytesMul(Bytes("base16", "0xFF"), Bytes("base16", "0xFE")) 0xFD02
BytesDiv(a, b) TealType.Bytes BytesDiv(Bytes("base16", "0xFF"), Bytes("base16", "0x11")) 0x0F
BytesMod(a, b) TealType.Bytes BytesMod(Bytes("base16", "0xFF"), Bytes("base16", "0x12")) 0x03
BytesAnd(a, b) TealType.Bytes BytesAnd(Bytes("base16", "0xBEEF"), Bytes("base16", "0x1337")) 0x1227
BytesOr(a, b) TealType.Bytes BytesOr(Bytes("base16", "0xBEEF"), Bytes("base16", "0x1337")) 0xBFFF
BytesXor(a, b) TealType.Bytes BytesXor(Bytes("base16", "0xBEEF"), Bytes("base16", "0x1337")) 0xADD8
BytesNot(a) TealType.Bytes BytesNot(Bytes("base16", "0xFF00")) 0x00FF
BytesZero(a) TealType.Bytes BytesZero(Int(4)) 0x00000000

Currently, byteslice arithmetic operations are not overloaded, and must be explicitly called.

Bit and Byte Operations

In addition to the standard arithmetic operators above, PyTeal also supports operations that manipulate the individual bits and bytes of PyTeal values.

To use these operations, you’ll need to provide an index specifying which bit or byte to access. These indexes have different meanings depending on whether you are manipulating integers or byte slices:

  • For integers, bit indexing begins with low-order bits. For example, the bit at index 4 of the integer 16 (000...0001000 in binary) is 1. Every other index has a bit value of 0. Any index less than 64 is valid, regardless of the integer’s value.

    Byte indexing is not supported for integers.

  • For byte strings, bit indexing begins at the first bit. For example, the bit at index 0 of the base16 byte string 0xf0 (11110000 in binary) is 1. Any index less than 4 has a bit value of 1, and any index 4 or greater has a bit value of 0. Any index less than 8 times the length of the byte string is valid.

    Likewise, byte indexing begins at the first byte of the string. For example, the byte at index 0 of that the base16 string 0xff00 (1111111100000000 in binary) is 255 (111111111 in binary), and the byte at index 1 is 0. Any index less than the length of the byte string is valid.

Bit Manipulation

The GetBit expression can extract individual bit values from integers and byte strings. For example,

GetBit(Int(16), Int(0)) # get the 0th bit of 16, produces 0
GetBit(Int(16), Int(4)) # get the 4th bit of 16, produces 1
GetBit(Int(16), Int(63)) # get the 63rd bit of 16, produces 0
GetBit(Int(16), Int(64)) # get the 64th bit of 16, invalid index

GetBit(Bytes("base16", "0xf0"), Int(0)) # get the 0th bit of 0xf0, produces 1
GetBit(Bytes("base16", "0xf0"), Int(7)) # get the 7th bit of 0xf0, produces 0
GetBit(Bytes("base16", "0xf0"), Int(8)) # get the 8th bit of 0xf0, invalid index

Additionally, the SetBit expression can modify individual bit values from integers and byte strings. For example,

SetBit(Int(0), Int(4), Int(1)) # set the 4th bit of 0 to 1, produces 16
SetBit(Int(4), Int(0), Int(1)) # set the 0th bit of 4 to 1, produces 5
SetBit(Int(4), Int(0), Int(0)) # set the 0th bit of 4 to 0, produces 4

SetBit(Bytes("base16", "0x00"), Int(0), Int(1)) # set the 0th bit of 0x00 to 1, produces 0x80
SetBit(Bytes("base16", "0x00"), Int(3), Int(1)) # set the 3rd bit of 0x00 to 1, produces 0x10
SetBit(Bytes("base16", "0x00"), Int(7), Int(1)) # set the 7th bit of 0x00 to 1, produces 0x01

Byte Manipulation

In addition to manipulating bits, individual bytes in byte strings can be manipulated.

The GetByte expression can extract individual bytes from byte strings. For example,

GetByte(Bytes("base16", "0xff00"), Int(0)) # get the 0th byte of 0xff00, produces 255
GetByte(Bytes("base16", "0xff00"), Int(1)) # get the 1st byte of 0xff00, produces 0
GetByte(Bytes("base16", "0xff00"), Int(2)) # get the 2nd byte of 0xff00, invalid index

GetByte(Bytes("abc"), Int(0)) # get the 0th byte of "abc", produces 97 (ASCII 'a')
GetByte(Bytes("abc"), Int(1)) # get the 1st byte of "abc", produces 98 (ASCII 'b')
GetByte(Bytes("abc"), Int(2)) # get the 2nd byte of "abc", produces 99 (ASCII 'c')

Additionally, the SetByte expression can modify individual bytes in byte strings. For example,

SetByte(Bytes("base16", "0xff00"), Int(0), Int(0)) # set the 0th byte of 0xff00 to 0, produces 0x0000
SetByte(Bytes("base16", "0xff00"), Int(0), Int(128)) # set the 0th byte of 0xff00 to 128, produces 0x8000

SetByte(Bytes("abc"), Int(0), Int(98)) # set the 0th byte of "abc" to 98 (ASCII 'b'), produces "bbc"
SetByte(Bytes("abc"), Int(1), Int(66)) # set the 1st byte of "abc" to 66 (ASCII 'B'), produces "aBc"