From 6d707b42efaeefb25aab4dfbf8829f72c7bf211e Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 11 Jul 2023 10:12:51 -0400 Subject: [PATCH 1/8] Upcoming changes for v10 1. LogicSig opcode budget pooling for non-delegated logicsigs 2. Elliptic curve ops on some pairing friendly curves (not yet in this PR) 3. Documentation improvements by using types to describe some opcodes. --- dev/TEAL.md | 157 ++++++---- dev/TEAL_opcodes.md | 726 ++++++++++++++++++++++++-------------------- 2 files changed, 503 insertions(+), 380 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 6e15188..df57937 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -48,6 +48,32 @@ has fewer than two elements, the operation fails. Some operations, like `frame_dig` and `proto` could fail because of an attempt to access above the current stack. +## Stack Types + +While every element of the stack is restricted to the types `uint64` and `bytes`, +the values of these types may be known to be bounded. The more common bounded types are +named to provide more semantic information in the documentation. They're also used during +assembly time to do type checking and to provide more informative error messages. + + +#### Definitions + +| Name | Bound | AVM Type | +| ---- | ---- | -------- | +| uint64 | x <= 18446744073709551615 | uint64 | +| stateKey | len(x) <= 64 | []byte | +| none | | none | +| method | len(x) == 4 | []byte | +| boxName | 1 <= len(x) <= 64 | []byte | +| bool | x <= 1 | uint64 | +| bigint | len(x) <= 64 | []byte | +| any | | any | +| address | len(x) == 32 | []byte | +| []byte | len(x) <= 4096 | []byte | +| [32]byte | len(x) == 32 | []byte | + + + ## Scratch Space In addition to the stack there are 256 positions of scratch @@ -104,31 +130,44 @@ A program can either authorize some delegated action on a normal signature-based or multisignature-based account or be wholly in charge of a contract account. -* If the account has signed the program (by providing a valid ed25519 - signature or valid multisignature for the authorizer address on the - string "Program" concatenated with the program bytecode) then: if the - program returns true the transaction is authorized as if the account - had signed it. This allows an account to hand out a signed program - so that other users can carry out delegated actions which are - approved by the program. Note that Smart Signature Args are _not_ - signed. - -* If the SHA512_256 hash of the program (prefixed by "Program") is - equal to authorizer address of the transaction sender then this is a - contract account wholly controlled by the program. No other - signature is necessary or possible. The only way to execute a - transaction against the contract account is for the program to - approve it. +* *Delegated Smart Signatures* --- If the account has signed the + program (by providing a valid ed25519 signature or valid + multisignature for the authorizer address on the string "Program" + concatenated with the program bytecode) then: if the program returns + true the transaction is authorized as if the account had signed + it. This allows an account to hand out a signed program so that + other users can carry out delegated actions which are approved by + the program. Note that Smart Signature Args are _not_ signed. + +* *Contract Smart Signatures* -- If the SHA512_256 hash of the program + (prefixed by "Program") is equal to authorizer address of the + transaction sender then this is a contract account wholly controlled + by the program. No other signature is necessary or possible. The + only way to execute a transaction against the contract account is + for the program to approve it. The bytecode plus the length of all Args must add up to no more than 1000 bytes (consensus parameter LogicSigMaxSize). Each opcode has an -associated cost and the program cost must total no more than 20,000 -(consensus parameter LogicSigMaxCost). Most opcodes have a cost of 1, -but a few slow cryptographic operations have a much higher cost. Prior -to v4, the program's cost was estimated as the static sum of all the -opcode costs in the program (whether they were actually executed or -not). Beginning with v4, the program's cost is tracked dynamically, -while being evaluated. If the program exceeds its budget, it fails. +associated cost, usually 1, but a few slow operations have higher +costs. Prior to v4, the program's cost was estimated as the static sum +of all the opcode costs in the program (whether they were actually +executed or not). Beginning with v4, the program's cost is tracked +dynamically, while being evaluated. If the program exceeds its budget, +it fails. + +The total program cost of a _delegated_ Smart Signature program must +no exceed 20,000 (consensus parameter LogicSigMaxCost). + +The total program cost of all _contract_ signatures in a group must +not exceed 20,000 (consensus parameter LogicSigMaxCost) times the +number of transactions in the group that are not signed by delegated +Smart Signatures. + +More intuitively --- Delegated Smart Signatures receive 20,000 opcode +units, which they are free to use, but are not shared. All other +transactions receive 20,000 opcode units each, which are shared among +the Contract Smart Signatures. + ## Execution Environment for Smart Contracts (Applications) @@ -499,18 +538,18 @@ Some of these have immediate data in the byte or bytes after the opcode. ##### Scalar Fields | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | -| 0 | Sender | []byte | | 32 byte address | +| 0 | Sender | address | | 32 byte address | | 1 | Fee | uint64 | | microalgos | | 2 | FirstValid | uint64 | | round number | | 3 | FirstValidTime | uint64 | v7 | UNIX timestamp of block before txn.FirstValid. Fails if negative | | 4 | LastValid | uint64 | | round number | | 5 | Note | []byte | | Any data up to 1024 bytes | -| 6 | Lease | []byte | | 32 byte lease value | -| 7 | Receiver | []byte | | 32 byte address | +| 6 | Lease | [32]byte | | 32 byte lease value | +| 7 | Receiver | address | | 32 byte address | | 8 | Amount | uint64 | | microalgos | -| 9 | CloseRemainderTo | []byte | | 32 byte address | -| 10 | VotePK | []byte | | 32 byte address | -| 11 | SelectionPK | []byte | | 32 byte address | +| 9 | CloseRemainderTo | address | | 32 byte address | +| 10 | VotePK | [32]byte | | 32 byte address | +| 11 | SelectionPK | [32]byte | | 32 byte address | | 12 | VoteFirst | uint64 | | The first round that the participation key is valid. | | 13 | VoteLast | uint64 | | The last round that the participation key is valid. | | 14 | VoteKeyDilution | uint64 | | Dilution for the 2-level participation key | @@ -518,33 +557,33 @@ Some of these have immediate data in the byte or bytes after the opcode. | 16 | TypeEnum | uint64 | | Transaction type as integer | | 17 | XferAsset | uint64 | | Asset ID | | 18 | AssetAmount | uint64 | | value in Asset's units | -| 19 | AssetSender | []byte | | 32 byte address. Source of assets if Sender is the Asset's Clawback address. | -| 20 | AssetReceiver | []byte | | 32 byte address | -| 21 | AssetCloseTo | []byte | | 32 byte address | +| 19 | AssetSender | address | | 32 byte address. Source of assets if Sender is the Asset's Clawback address. | +| 20 | AssetReceiver | address | | 32 byte address | +| 21 | AssetCloseTo | address | | 32 byte address | | 22 | GroupIndex | uint64 | | Position of this transaction within an atomic transaction group. A stand-alone transaction is implicitly element 0 in a group of 1 | -| 23 | TxID | []byte | | The computed ID for this transaction. 32 bytes. | +| 23 | TxID | [32]byte | | The computed ID for this transaction. 32 bytes. | | 24 | ApplicationID | uint64 | v2 | ApplicationID from ApplicationCall transaction | | 25 | OnCompletion | uint64 | v2 | ApplicationCall transaction on completion action | | 27 | NumAppArgs | uint64 | v2 | Number of ApplicationArgs | | 29 | NumAccounts | uint64 | v2 | Number of Accounts | | 30 | ApprovalProgram | []byte | v2 | Approval program | | 31 | ClearStateProgram | []byte | v2 | Clear state program | -| 32 | RekeyTo | []byte | v2 | 32 byte Sender's new AuthAddr | +| 32 | RekeyTo | address | v2 | 32 byte Sender's new AuthAddr | | 33 | ConfigAsset | uint64 | v2 | Asset ID in asset config transaction | | 34 | ConfigAssetTotal | uint64 | v2 | Total number of units of this asset created | | 35 | ConfigAssetDecimals | uint64 | v2 | Number of digits to display after the decimal place when displaying the asset | -| 36 | ConfigAssetDefaultFrozen | uint64 | v2 | Whether the asset's slots are frozen by default or not, 0 or 1 | +| 36 | ConfigAssetDefaultFrozen | bool | v2 | Whether the asset's slots are frozen by default or not, 0 or 1 | | 37 | ConfigAssetUnitName | []byte | v2 | Unit name of the asset | | 38 | ConfigAssetName | []byte | v2 | The asset name | | 39 | ConfigAssetURL | []byte | v2 | URL | -| 40 | ConfigAssetMetadataHash | []byte | v2 | 32 byte commitment to unspecified asset metadata | -| 41 | ConfigAssetManager | []byte | v2 | 32 byte address | -| 42 | ConfigAssetReserve | []byte | v2 | 32 byte address | -| 43 | ConfigAssetFreeze | []byte | v2 | 32 byte address | -| 44 | ConfigAssetClawback | []byte | v2 | 32 byte address | +| 40 | ConfigAssetMetadataHash | [32]byte | v2 | 32 byte commitment to unspecified asset metadata | +| 41 | ConfigAssetManager | address | v2 | 32 byte address | +| 42 | ConfigAssetReserve | address | v2 | 32 byte address | +| 43 | ConfigAssetFreeze | address | v2 | 32 byte address | +| 44 | ConfigAssetClawback | address | v2 | 32 byte address | | 45 | FreezeAsset | uint64 | v2 | Asset ID being frozen or un-frozen | -| 46 | FreezeAssetAccount | []byte | v2 | 32 byte address of the account whose asset slot is being frozen or un-frozen | -| 47 | FreezeAssetFrozen | uint64 | v2 | The new frozen value, 0 or 1 | +| 46 | FreezeAssetAccount | address | v2 | 32 byte address of the account whose asset slot is being frozen or un-frozen | +| 47 | FreezeAssetFrozen | bool | v2 | The new frozen value, 0 or 1 | | 49 | NumAssets | uint64 | v3 | Number of Assets | | 51 | NumApplications | uint64 | v3 | Number of Applications | | 52 | GlobalNumUint | uint64 | v3 | Number of global state integers in ApplicationCall | @@ -552,7 +591,7 @@ Some of these have immediate data in the byte or bytes after the opcode. | 54 | LocalNumUint | uint64 | v3 | Number of local state integers in ApplicationCall | | 55 | LocalNumByteSlice | uint64 | v3 | Number of local state byteslices in ApplicationCall | | 56 | ExtraProgramPages | uint64 | v4 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. | -| 57 | Nonparticipation | uint64 | v5 | Marks an account nonparticipating for rewards | +| 57 | Nonparticipation | bool | v5 | Marks an account nonparticipating for rewards | | 59 | NumLogs | uint64 | v5 | Number of Logs (only with `itxn` in v5). Application mode only | | 60 | CreatedAssetID | uint64 | v5 | Asset ID allocated by the creation of an ASA (only with `itxn` in v5). Application mode only | | 61 | CreatedApplicationID | uint64 | v5 | ApplicationID allocated by the creation of an application (only with `itxn` in v5). Application mode only | @@ -565,7 +604,7 @@ Some of these have immediate data in the byte or bytes after the opcode. | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | | 26 | ApplicationArgs | []byte | v2 | Arguments passed to the application in the ApplicationCall transaction | -| 28 | Accounts | []byte | v2 | Accounts listed in the ApplicationCall transaction | +| 28 | Accounts | address | v2 | Accounts listed in the ApplicationCall transaction | | 48 | Assets | uint64 | v3 | Foreign Assets listed in the ApplicationCall transaction | | 50 | Applications | uint64 | v3 | Foreign Apps listed in the ApplicationCall transaction | | 58 | Logs | []byte | v5 | Log messages emitted by an application call (only with `itxn` in v5). Application mode only | @@ -584,18 +623,18 @@ Global fields are fields that are common to all the transactions in the group. I | 0 | MinTxnFee | uint64 | | microalgos | | 1 | MinBalance | uint64 | | microalgos | | 2 | MaxTxnLife | uint64 | | rounds | -| 3 | ZeroAddress | []byte | | 32 byte address of all zero bytes | +| 3 | ZeroAddress | address | | 32 byte address of all zero bytes | | 4 | GroupSize | uint64 | | Number of transactions in this atomic transaction group. At least 1 | | 5 | LogicSigVersion | uint64 | v2 | Maximum supported version | | 6 | Round | uint64 | v2 | Current round number. Application mode only. | | 7 | LatestTimestamp | uint64 | v2 | Last confirmed block UNIX timestamp. Fails if negative. Application mode only. | | 8 | CurrentApplicationID | uint64 | v2 | ID of current application executing. Application mode only. | -| 9 | CreatorAddress | []byte | v3 | Address of the creator of the current application. Application mode only. | -| 10 | CurrentApplicationAddress | []byte | v5 | Address that the current application controls. Application mode only. | -| 11 | GroupID | []byte | v5 | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. | +| 9 | CreatorAddress | address | v3 | Address of the creator of the current application. Application mode only. | +| 10 | CurrentApplicationAddress | address | v5 | Address that the current application controls. Application mode only. | +| 11 | GroupID | [32]byte | v5 | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. | | 12 | OpcodeBudget | uint64 | v6 | The remaining cost that can be spent by opcodes in this program. | | 13 | CallerApplicationID | uint64 | v6 | The application ID of the application that called this application. 0 if this application is at the top-level. Application mode only. | -| 14 | CallerApplicationAddress | []byte | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | +| 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | **Asset Fields** @@ -605,23 +644,23 @@ Asset fields include `AssetHolding` and `AssetParam` fields that are used in the | Index | Name | Type | Notes | | - | ------ | -- | --------- | | 0 | AssetBalance | uint64 | Amount of the asset unit held by this account | -| 1 | AssetFrozen | uint64 | Is the asset frozen or not | +| 1 | AssetFrozen | bool | Is the asset frozen or not | | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | | 0 | AssetTotal | uint64 | | Total number of units of this asset | | 1 | AssetDecimals | uint64 | | See AssetParams.Decimals | -| 2 | AssetDefaultFrozen | uint64 | | Frozen by default or not | +| 2 | AssetDefaultFrozen | bool | | Frozen by default or not | | 3 | AssetUnitName | []byte | | Asset unit name | | 4 | AssetName | []byte | | Asset name | | 5 | AssetURL | []byte | | URL with additional info about the asset | -| 6 | AssetMetadataHash | []byte | | Arbitrary commitment | -| 7 | AssetManager | []byte | | Manager address | -| 8 | AssetReserve | []byte | | Reserve address | -| 9 | AssetFreeze | []byte | | Freeze address | -| 10 | AssetClawback | []byte | | Clawback address | -| 11 | AssetCreator | []byte | v5 | Creator address | +| 6 | AssetMetadataHash | [32]byte | | Arbitrary commitment | +| 7 | AssetManager | address | | Manager address | +| 8 | AssetReserve | address | | Reserve address | +| 9 | AssetFreeze | address | | Freeze address | +| 10 | AssetClawback | address | | Clawback address | +| 11 | AssetCreator | address | v5 | Creator address | **App Fields** @@ -637,8 +676,8 @@ App fields used in the `app_params_get` opcode. | 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | | 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | | 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | -| 7 | AppCreator | []byte | Creator address | -| 8 | AppAddress | []byte | Address for which this application has authority | +| 7 | AppCreator | address | Creator address | +| 8 | AppAddress | address | Address for which this application has authority | **Account Fields** @@ -649,7 +688,7 @@ Account fields used in the `acct_params_get` opcode. | - | ------ | -- | - | --------- | | 0 | AcctBalance | uint64 | | Account balance in microalgos | | 1 | AcctMinBalance | uint64 | | Minimum required balance for account, in microalgos | -| 2 | AcctAuthAddr | []byte | | Address the account is rekeyed to. | +| 2 | AcctAuthAddr | address | | Address the account is rekeyed to. | | 3 | AcctTotalNumUint | uint64 | v8 | The total number of uint64 values allocated by this account in Global and Local States. | | 4 | AcctTotalNumByteSlice | uint64 | v8 | The total number of byte array values allocated by this account in Global and Local States. | | 5 | AcctTotalExtraAppPages | uint64 | v8 | The number of extra app code pages used by this account. | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index b3559ba..0807379 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -13,14 +13,14 @@ Ops have a 'cost' of 1 unless otherwise specified. ## err -- Opcode: 0x00 +- Bytecode: 0x00 - Stack: ... → _exits_ - Fail immediately. ## sha256 -- Opcode: 0x01 -- Stack: ..., A: []byte → ..., []byte +- Bytecode: 0x01 +- Stack: ..., A: []byte → ..., [32]byte - SHA256 hash of value A, yields [32]byte - **Cost**: - 7 (v1) @@ -28,8 +28,8 @@ Ops have a 'cost' of 1 unless otherwise specified. ## keccak256 -- Opcode: 0x02 -- Stack: ..., A: []byte → ..., []byte +- Bytecode: 0x02 +- Stack: ..., A: []byte → ..., [32]byte - Keccak256 hash of value A, yields [32]byte - **Cost**: - 26 (v1) @@ -37,8 +37,8 @@ Ops have a 'cost' of 1 unless otherwise specified. ## sha512_256 -- Opcode: 0x03 -- Stack: ..., A: []byte → ..., []byte +- Bytecode: 0x03 +- Stack: ..., A: []byte → ..., [32]byte - SHA512_256 hash of value A, yields [32]byte - **Cost**: - 9 (v1) @@ -46,22 +46,25 @@ Ops have a 'cost' of 1 unless otherwise specified. ## ed25519verify -- Opcode: 0x04 -- Stack: ..., A: []byte, B: []byte, C: []byte → ..., uint64 +- Bytecode: 0x04 +- Stack: ..., A: []byte, B: []byte, C: []byte → ..., bool - for (data A, signature B, pubkey C) verify the signature of ("ProgData" || program_hash || data) against the pubkey => {0 or 1} - **Cost**: 1900 The 32 byte public key is the last element on the stack, preceded by the 64 byte signature at the second-to-last element on the stack, preceded by the data which was signed at the third-to-last element on the stack. -## ecdsa_verify v +## ecdsa_verify -- Opcode: 0x05 {uint8 curve index} -- Stack: ..., A: []byte, B: []byte, C: []byte, D: []byte, E: []byte → ..., uint64 +- Syntax: `ecdsa_verify V` ∋ V: [ECDSA](#field-group-ecdsa) +- Bytecode: 0x05 {uint8} +- Stack: ..., A: []byte, B: []byte, C: []byte, D: []byte, E: []byte → ..., bool - for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} - **Cost**: Secp256k1=1700 Secp256r1=2500 - Availability: v5 -`ECDSA` Curves: +### ECDSA + +Curves | Index | Name | In | Notes | | - | ------ | - | --------- | @@ -71,9 +74,10 @@ The 32 byte public key is the last element on the stack, preceded by the 64 byte The 32 byte Y-component of a public key is the last element on the stack, preceded by X-component of a pubkey, preceded by S and R components of a signature, preceded by the data that is fifth element on the stack. All values are big-endian encoded. The signed data must be 32 bytes long, and signatures in lower-S form are only accepted. -## ecdsa_pk_decompress v +## ecdsa_pk_decompress -- Opcode: 0x06 {uint8 curve index} +- Syntax: `ecdsa_pk_decompress V` ∋ V: [ECDSA](#field-group-ecdsa) +- Bytecode: 0x06 {uint8} - Stack: ..., A: []byte → ..., X: []byte, Y: []byte - decompress pubkey A into components X, Y - **Cost**: Secp256k1=650 Secp256r1=2400 @@ -81,9 +85,10 @@ The 32 byte Y-component of a public key is the last element on the stack, preced The 33 byte public key in a compressed form to be decompressed into X and Y (top) components. All values are big-endian encoded. -## ecdsa_pk_recover v +## ecdsa_pk_recover -- Opcode: 0x07 {uint8 curve index} +- Syntax: `ecdsa_pk_recover V` ∋ V: [ECDSA](#field-group-ecdsa) +- Bytecode: 0x07 {uint8} - Stack: ..., A: []byte, B: uint64, C: []byte, D: []byte → ..., X: []byte, Y: []byte - for (data A, recovery id B, signature C, D) recover a public key - **Cost**: 2000 @@ -93,7 +98,7 @@ S (top) and R elements of a signature, recovery id and data (bottom) are expecte ## + -- Opcode: 0x08 +- Bytecode: 0x08 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A plus B. Fail on overflow. @@ -101,13 +106,13 @@ Overflow is an error condition which halts execution and fails the transaction. ## - -- Opcode: 0x09 +- Bytecode: 0x09 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A minus B. Fail if B > A. ## / -- Opcode: 0x0a +- Bytecode: 0x0a - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A divided by B (truncated division). Fail if B == 0. @@ -115,7 +120,7 @@ Overflow is an error condition which halts execution and fails the transaction. ## * -- Opcode: 0x0b +- Bytecode: 0x0b - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A times B. Fail on overflow. @@ -123,73 +128,73 @@ Overflow is an error condition which halts execution and fails the transaction. ## < -- Opcode: 0x0c -- Stack: ..., A: uint64, B: uint64 → ..., uint64 +- Bytecode: 0x0c +- Stack: ..., A: uint64, B: uint64 → ..., bool - A less than B => {0 or 1} ## > -- Opcode: 0x0d -- Stack: ..., A: uint64, B: uint64 → ..., uint64 +- Bytecode: 0x0d +- Stack: ..., A: uint64, B: uint64 → ..., bool - A greater than B => {0 or 1} ## <= -- Opcode: 0x0e -- Stack: ..., A: uint64, B: uint64 → ..., uint64 +- Bytecode: 0x0e +- Stack: ..., A: uint64, B: uint64 → ..., bool - A less than or equal to B => {0 or 1} ## >= -- Opcode: 0x0f -- Stack: ..., A: uint64, B: uint64 → ..., uint64 +- Bytecode: 0x0f +- Stack: ..., A: uint64, B: uint64 → ..., bool - A greater than or equal to B => {0 or 1} ## && -- Opcode: 0x10 -- Stack: ..., A: uint64, B: uint64 → ..., uint64 +- Bytecode: 0x10 +- Stack: ..., A: uint64, B: uint64 → ..., bool - A is not zero and B is not zero => {0 or 1} ## || -- Opcode: 0x11 -- Stack: ..., A: uint64, B: uint64 → ..., uint64 +- Bytecode: 0x11 +- Stack: ..., A: uint64, B: uint64 → ..., bool - A is not zero or B is not zero => {0 or 1} ## == -- Opcode: 0x12 -- Stack: ..., A, B → ..., uint64 +- Bytecode: 0x12 +- Stack: ..., A, B → ..., bool - A is equal to B => {0 or 1} ## != -- Opcode: 0x13 -- Stack: ..., A, B → ..., uint64 +- Bytecode: 0x13 +- Stack: ..., A, B → ..., bool - A is not equal to B => {0 or 1} ## ! -- Opcode: 0x14 +- Bytecode: 0x14 - Stack: ..., A: uint64 → ..., uint64 - A == 0 yields 1; else 0 ## len -- Opcode: 0x15 +- Bytecode: 0x15 - Stack: ..., A: []byte → ..., uint64 - yields length of byte value A ## itob -- Opcode: 0x16 +- Bytecode: 0x16 - Stack: ..., A: uint64 → ..., []byte - converts uint64 A to big-endian byte array, always of length 8 ## btoi -- Opcode: 0x17 +- Bytecode: 0x17 - Stack: ..., A: []byte → ..., uint64 - converts big-endian byte array A to uint64. Fails if len(A) > 8. Padded by leading 0s if len(A) < 8. @@ -197,50 +202,50 @@ Overflow is an error condition which halts execution and fails the transaction. ## % -- Opcode: 0x18 +- Bytecode: 0x18 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A modulo B. Fail if B == 0. ## | -- Opcode: 0x19 +- Bytecode: 0x19 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A bitwise-or B ## & -- Opcode: 0x1a +- Bytecode: 0x1a - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A bitwise-and B ## ^ -- Opcode: 0x1b +- Bytecode: 0x1b - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A bitwise-xor B ## ~ -- Opcode: 0x1c +- Bytecode: 0x1c - Stack: ..., A: uint64 → ..., uint64 - bitwise invert value A ## mulw -- Opcode: 0x1d +- Bytecode: 0x1d - Stack: ..., A: uint64, B: uint64 → ..., X: uint64, Y: uint64 - A times B as a 128-bit result in two uint64s. X is the high 64 bits, Y is the low ## addw -- Opcode: 0x1e +- Bytecode: 0x1e - Stack: ..., A: uint64, B: uint64 → ..., X: uint64, Y: uint64 - A plus B as a 128-bit result. X is the carry-bit, Y is the low-order 64 bits. - Availability: v2 ## divmodw -- Opcode: 0x1f +- Bytecode: 0x1f - Stack: ..., A: uint64, B: uint64, C: uint64, D: uint64 → ..., W: uint64, X: uint64, Y: uint64, Z: uint64 - W,X = (A,B / C,D); Y,Z = (A,B modulo C,D) - **Cost**: 20 @@ -248,139 +253,147 @@ Overflow is an error condition which halts execution and fails the transaction. The notation J,K indicates that two uint64 values J and K are interpreted as a uint128 value, with J as the high uint64 and K the low. -## intcblock uint ... +## intcblock -- Opcode: 0x20 {varuint count} [{varuint value}, ...] +- Syntax: `intcblock UINT ...` ∋ UINT ...: a block of int constant values +- Bytecode: 0x20 {varuint count, [varuint ...]} - Stack: ... → ... - prepare block of uint64 constants for use by intc `intcblock` loads following program bytes into an array of integer constants in the evaluator. These integer constants can be referred to by `intc` and `intc_*` which will push the value onto the stack. Subsequent calls to `intcblock` reset and replace the integer constants available to the script. -## intc i +## intc -- Opcode: 0x21 {uint8 int constant index} +- Syntax: `intc I` ∋ I: an index in the intcblock +- Bytecode: 0x21 {uint8} - Stack: ... → ..., uint64 - Ith constant from intcblock ## intc_0 -- Opcode: 0x22 +- Bytecode: 0x22 - Stack: ... → ..., uint64 - constant 0 from intcblock ## intc_1 -- Opcode: 0x23 +- Bytecode: 0x23 - Stack: ... → ..., uint64 - constant 1 from intcblock ## intc_2 -- Opcode: 0x24 +- Bytecode: 0x24 - Stack: ... → ..., uint64 - constant 2 from intcblock ## intc_3 -- Opcode: 0x25 +- Bytecode: 0x25 - Stack: ... → ..., uint64 - constant 3 from intcblock -## bytecblock bytes ... +## bytecblock -- Opcode: 0x26 {varuint count} [({varuint length} bytes), ...] +- Syntax: `bytecblock BYTES ...` ∋ BYTES ...: a block of byte constant values +- Bytecode: 0x26 {varuint count, [varuint length, bytes ...]} - Stack: ... → ... - prepare block of byte-array constants for use by bytec `bytecblock` loads the following program bytes into an array of byte-array constants in the evaluator. These constants can be referred to by `bytec` and `bytec_*` which will push the value onto the stack. Subsequent calls to `bytecblock` reset and replace the bytes constants available to the script. -## bytec i +## bytec -- Opcode: 0x27 {uint8 byte constant index} +- Syntax: `bytec I` ∋ I: an index in the bytecblock +- Bytecode: 0x27 {uint8} - Stack: ... → ..., []byte - Ith constant from bytecblock ## bytec_0 -- Opcode: 0x28 +- Bytecode: 0x28 - Stack: ... → ..., []byte - constant 0 from bytecblock ## bytec_1 -- Opcode: 0x29 +- Bytecode: 0x29 - Stack: ... → ..., []byte - constant 1 from bytecblock ## bytec_2 -- Opcode: 0x2a +- Bytecode: 0x2a - Stack: ... → ..., []byte - constant 2 from bytecblock ## bytec_3 -- Opcode: 0x2b +- Bytecode: 0x2b - Stack: ... → ..., []byte - constant 3 from bytecblock -## arg n +## arg -- Opcode: 0x2c {uint8 arg index} +- Syntax: `arg N` ∋ N: an arg index +- Bytecode: 0x2c {uint8} - Stack: ... → ..., []byte - Nth LogicSig argument - Mode: Signature ## arg_0 -- Opcode: 0x2d +- Bytecode: 0x2d - Stack: ... → ..., []byte - LogicSig argument 0 - Mode: Signature ## arg_1 -- Opcode: 0x2e +- Bytecode: 0x2e - Stack: ... → ..., []byte - LogicSig argument 1 - Mode: Signature ## arg_2 -- Opcode: 0x2f +- Bytecode: 0x2f - Stack: ... → ..., []byte - LogicSig argument 2 - Mode: Signature ## arg_3 -- Opcode: 0x30 +- Bytecode: 0x30 - Stack: ... → ..., []byte - LogicSig argument 3 - Mode: Signature -## txn f +## txn -- Opcode: 0x31 {uint8 transaction field index} +- Syntax: `txn F` ∋ F: [txn](#field-group-txn) +- Bytecode: 0x31 {uint8} - Stack: ... → ..., any - field F of current transaction -`txn` Fields (see [transaction reference](https://developer.algorand.org/docs/reference/transactions/)): +### txn + +Fields (see [transaction reference](https://developer.algorand.org/docs/reference/transactions/)) | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | -| 0 | Sender | []byte | | 32 byte address | +| 0 | Sender | address | | 32 byte address | | 1 | Fee | uint64 | | microalgos | | 2 | FirstValid | uint64 | | round number | | 3 | FirstValidTime | uint64 | v7 | UNIX timestamp of block before txn.FirstValid. Fails if negative | | 4 | LastValid | uint64 | | round number | | 5 | Note | []byte | | Any data up to 1024 bytes | -| 6 | Lease | []byte | | 32 byte lease value | -| 7 | Receiver | []byte | | 32 byte address | +| 6 | Lease | [32]byte | | 32 byte lease value | +| 7 | Receiver | address | | 32 byte address | | 8 | Amount | uint64 | | microalgos | -| 9 | CloseRemainderTo | []byte | | 32 byte address | -| 10 | VotePK | []byte | | 32 byte address | -| 11 | SelectionPK | []byte | | 32 byte address | +| 9 | CloseRemainderTo | address | | 32 byte address | +| 10 | VotePK | [32]byte | | 32 byte address | +| 11 | SelectionPK | [32]byte | | 32 byte address | | 12 | VoteFirst | uint64 | | The first round that the participation key is valid. | | 13 | VoteLast | uint64 | | The last round that the participation key is valid. | | 14 | VoteKeyDilution | uint64 | | Dilution for the 2-level participation key | @@ -388,33 +401,33 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u | 16 | TypeEnum | uint64 | | Transaction type as integer | | 17 | XferAsset | uint64 | | Asset ID | | 18 | AssetAmount | uint64 | | value in Asset's units | -| 19 | AssetSender | []byte | | 32 byte address. Source of assets if Sender is the Asset's Clawback address. | -| 20 | AssetReceiver | []byte | | 32 byte address | -| 21 | AssetCloseTo | []byte | | 32 byte address | +| 19 | AssetSender | address | | 32 byte address. Source of assets if Sender is the Asset's Clawback address. | +| 20 | AssetReceiver | address | | 32 byte address | +| 21 | AssetCloseTo | address | | 32 byte address | | 22 | GroupIndex | uint64 | | Position of this transaction within an atomic transaction group. A stand-alone transaction is implicitly element 0 in a group of 1 | -| 23 | TxID | []byte | | The computed ID for this transaction. 32 bytes. | +| 23 | TxID | [32]byte | | The computed ID for this transaction. 32 bytes. | | 24 | ApplicationID | uint64 | v2 | ApplicationID from ApplicationCall transaction | | 25 | OnCompletion | uint64 | v2 | ApplicationCall transaction on completion action | | 27 | NumAppArgs | uint64 | v2 | Number of ApplicationArgs | | 29 | NumAccounts | uint64 | v2 | Number of Accounts | | 30 | ApprovalProgram | []byte | v2 | Approval program | | 31 | ClearStateProgram | []byte | v2 | Clear state program | -| 32 | RekeyTo | []byte | v2 | 32 byte Sender's new AuthAddr | +| 32 | RekeyTo | address | v2 | 32 byte Sender's new AuthAddr | | 33 | ConfigAsset | uint64 | v2 | Asset ID in asset config transaction | | 34 | ConfigAssetTotal | uint64 | v2 | Total number of units of this asset created | | 35 | ConfigAssetDecimals | uint64 | v2 | Number of digits to display after the decimal place when displaying the asset | -| 36 | ConfigAssetDefaultFrozen | uint64 | v2 | Whether the asset's slots are frozen by default or not, 0 or 1 | +| 36 | ConfigAssetDefaultFrozen | bool | v2 | Whether the asset's slots are frozen by default or not, 0 or 1 | | 37 | ConfigAssetUnitName | []byte | v2 | Unit name of the asset | | 38 | ConfigAssetName | []byte | v2 | The asset name | | 39 | ConfigAssetURL | []byte | v2 | URL | -| 40 | ConfigAssetMetadataHash | []byte | v2 | 32 byte commitment to unspecified asset metadata | -| 41 | ConfigAssetManager | []byte | v2 | 32 byte address | -| 42 | ConfigAssetReserve | []byte | v2 | 32 byte address | -| 43 | ConfigAssetFreeze | []byte | v2 | 32 byte address | -| 44 | ConfigAssetClawback | []byte | v2 | 32 byte address | +| 40 | ConfigAssetMetadataHash | [32]byte | v2 | 32 byte commitment to unspecified asset metadata | +| 41 | ConfigAssetManager | address | v2 | 32 byte address | +| 42 | ConfigAssetReserve | address | v2 | 32 byte address | +| 43 | ConfigAssetFreeze | address | v2 | 32 byte address | +| 44 | ConfigAssetClawback | address | v2 | 32 byte address | | 45 | FreezeAsset | uint64 | v2 | Asset ID being frozen or un-frozen | -| 46 | FreezeAssetAccount | []byte | v2 | 32 byte address of the account whose asset slot is being frozen or un-frozen | -| 47 | FreezeAssetFrozen | uint64 | v2 | The new frozen value, 0 or 1 | +| 46 | FreezeAssetAccount | address | v2 | 32 byte address of the account whose asset slot is being frozen or un-frozen | +| 47 | FreezeAssetFrozen | bool | v2 | The new frozen value, 0 or 1 | | 49 | NumAssets | uint64 | v3 | Number of Assets | | 51 | NumApplications | uint64 | v3 | Number of Applications | | 52 | GlobalNumUint | uint64 | v3 | Number of global state integers in ApplicationCall | @@ -422,7 +435,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u | 54 | LocalNumUint | uint64 | v3 | Number of local state integers in ApplicationCall | | 55 | LocalNumByteSlice | uint64 | v3 | Number of local state byteslices in ApplicationCall | | 56 | ExtraProgramPages | uint64 | v4 | Number of additional pages for each of the application's approval and clear state programs. An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. | -| 57 | Nonparticipation | uint64 | v5 | Marks an account nonparticipating for rewards | +| 57 | Nonparticipation | bool | v5 | Marks an account nonparticipating for rewards | | 59 | NumLogs | uint64 | v5 | Number of Logs (only with `itxn` in v5). Application mode only | | 60 | CreatedAssetID | uint64 | v5 | Asset ID allocated by the creation of an ASA (only with `itxn` in v5). Application mode only | | 61 | CreatedApplicationID | uint64 | v5 | ApplicationID allocated by the creation of an application (only with `itxn` in v5). Application mode only | @@ -432,66 +445,75 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u | 67 | NumClearStateProgramPages | uint64 | v7 | Number of ClearState Program pages | -## global f +## global -- Opcode: 0x32 {uint8 global field index} +- Syntax: `global F` ∋ F: [global](#field-group-global) +- Bytecode: 0x32 {uint8} - Stack: ... → ..., any - global field F -`global` Fields: +### global + +Fields | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | | 0 | MinTxnFee | uint64 | | microalgos | | 1 | MinBalance | uint64 | | microalgos | | 2 | MaxTxnLife | uint64 | | rounds | -| 3 | ZeroAddress | []byte | | 32 byte address of all zero bytes | +| 3 | ZeroAddress | address | | 32 byte address of all zero bytes | | 4 | GroupSize | uint64 | | Number of transactions in this atomic transaction group. At least 1 | | 5 | LogicSigVersion | uint64 | v2 | Maximum supported version | | 6 | Round | uint64 | v2 | Current round number. Application mode only. | | 7 | LatestTimestamp | uint64 | v2 | Last confirmed block UNIX timestamp. Fails if negative. Application mode only. | | 8 | CurrentApplicationID | uint64 | v2 | ID of current application executing. Application mode only. | -| 9 | CreatorAddress | []byte | v3 | Address of the creator of the current application. Application mode only. | -| 10 | CurrentApplicationAddress | []byte | v5 | Address that the current application controls. Application mode only. | -| 11 | GroupID | []byte | v5 | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. | +| 9 | CreatorAddress | address | v3 | Address of the creator of the current application. Application mode only. | +| 10 | CurrentApplicationAddress | address | v5 | Address that the current application controls. Application mode only. | +| 11 | GroupID | [32]byte | v5 | ID of the transaction group. 32 zero bytes if the transaction is not part of a group. | | 12 | OpcodeBudget | uint64 | v6 | The remaining cost that can be spent by opcodes in this program. | | 13 | CallerApplicationID | uint64 | v6 | The application ID of the application that called this application. 0 if this application is at the top-level. Application mode only. | -| 14 | CallerApplicationAddress | []byte | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | +| 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | -## gtxn t f +## gtxn -- Opcode: 0x33 {uint8 transaction group index} {uint8 transaction field index} +- Syntax: `gtxn T F` ∋ T: transaction group index, F: [txn](#field-group-txn) +- Bytecode: 0x33 {uint8}, {uint8} - Stack: ... → ..., any - field F of the Tth transaction in the current group for notes on transaction fields available, see `txn`. If this transaction is _i_ in the group, `gtxn i field` is equivalent to `txn field`. -## load i +## load -- Opcode: 0x34 {uint8 position in scratch space to load from} +- Syntax: `load I` ∋ I: position in scratch space to load from +- Bytecode: 0x34 {uint8} - Stack: ... → ..., any - Ith scratch space value. All scratch spaces are 0 at program start. -## store i +## store -- Opcode: 0x35 {uint8 position in scratch space to store to} +- Syntax: `store I` ∋ I: position in scratch space to store to +- Bytecode: 0x35 {uint8} - Stack: ..., A → ... - store A to the Ith scratch space -## txna f i +## txna -- Opcode: 0x36 {uint8 transaction field index} {uint8 transaction field array index} +- Syntax: `txna F I` ∋ F: [txna](#field-group-txna), I: transaction field array index +- Bytecode: 0x36 {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F of the current transaction
`txna` can be called using `txn` with 2 immediates. - Availability: v2 -`txna` Fields (see [transaction reference](https://developer.algorand.org/docs/reference/transactions/)): +### txna + +Fields (see [transaction reference](https://developer.algorand.org/docs/reference/transactions/)) | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | | 26 | ApplicationArgs | []byte | v2 | Arguments passed to the application in the ApplicationCall transaction | -| 28 | Accounts | []byte | v2 | Accounts listed in the ApplicationCall transaction | +| 28 | Accounts | address | v2 | Accounts listed in the ApplicationCall transaction | | 48 | Assets | uint64 | v3 | Foreign Assets listed in the ApplicationCall transaction | | 50 | Applications | uint64 | v3 | Foreign Apps listed in the ApplicationCall transaction | | 58 | Logs | []byte | v5 | Log messages emitted by an application call (only with `itxn` in v5). Application mode only | @@ -499,32 +521,36 @@ for notes on transaction fields available, see `txn`. If this transaction is _i_ | 66 | ClearStateProgramPages | []byte | v7 | ClearState Program as an array of pages | -## gtxna t f i +## gtxna -- Opcode: 0x37 {uint8 transaction group index} {uint8 transaction field index} {uint8 transaction field array index} +- Syntax: `gtxna T F I` ∋ T: transaction group index, F: [txna](#field-group-txna), I: transaction field array index +- Bytecode: 0x37 {uint8}, {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F from the Tth transaction in the current group
`gtxna` can be called using `gtxn` with 3 immediates. - Availability: v2 -## gtxns f +## gtxns -- Opcode: 0x38 {uint8 transaction field index} +- Syntax: `gtxns F` ∋ F: [txn](#field-group-txn) +- Bytecode: 0x38 {uint8} - Stack: ..., A: uint64 → ..., any - field F of the Ath transaction in the current group - Availability: v3 for notes on transaction fields available, see `txn`. If top of stack is _i_, `gtxns field` is equivalent to `gtxn _i_ field`. gtxns exists so that _i_ can be calculated, often based on the index of the current transaction. -## gtxnsa f i +## gtxnsa -- Opcode: 0x39 {uint8 transaction field index} {uint8 transaction field array index} +- Syntax: `gtxnsa F I` ∋ F: [txna](#field-group-txna), I: transaction field array index +- Bytecode: 0x39 {uint8}, {uint8} - Stack: ..., A: uint64 → ..., any - Ith value of the array field F from the Ath transaction in the current group
`gtxnsa` can be called using `gtxns` with 2 immediates. - Availability: v3 -## gload t i +## gload -- Opcode: 0x3a {uint8 transaction group index} {uint8 position in scratch space to load from} +- Syntax: `gload T I` ∋ T: transaction group index, I: position in scratch space to load from +- Bytecode: 0x3a {uint8}, {uint8} - Stack: ... → ..., any - Ith scratch space value of the Tth transaction in the current group - Availability: v4 @@ -532,9 +558,10 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g `gload` fails unless the requested transaction is an ApplicationCall and T < GroupIndex. -## gloads i +## gloads -- Opcode: 0x3b {uint8 position in scratch space to load from} +- Syntax: `gloads I` ∋ I: position in scratch space to load from +- Bytecode: 0x3b {uint8} - Stack: ..., A: uint64 → ..., any - Ith scratch space value of the Ath transaction in the current group - Availability: v4 @@ -542,9 +569,10 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g `gloads` fails unless the requested transaction is an ApplicationCall and A < GroupIndex. -## gaid t +## gaid -- Opcode: 0x3c {uint8 transaction group index} +- Syntax: `gaid T` ∋ T: transaction group index +- Bytecode: 0x3c {uint8} - Stack: ... → ..., uint64 - ID of the asset or application created in the Tth transaction of the current group - Availability: v4 @@ -554,7 +582,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## gaids -- Opcode: 0x3d +- Bytecode: 0x3d - Stack: ..., A: uint64 → ..., uint64 - ID of the asset or application created in the Ath transaction of the current group - Availability: v4 @@ -564,21 +592,22 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## loads -- Opcode: 0x3e +- Bytecode: 0x3e - Stack: ..., A: uint64 → ..., any - Ath scratch space value. All scratch spaces are 0 at program start. - Availability: v5 ## stores -- Opcode: 0x3f +- Bytecode: 0x3f - Stack: ..., A: uint64, B → ... - store B to the Ath scratch space - Availability: v5 -## bnz target +## bnz -- Opcode: 0x40 {int16 branch offset, big-endian} +- Syntax: `bnz TARGET` ∋ TARGET: branch offset +- Bytecode: 0x40 {int16 (big-endian)} - Stack: ..., A: uint64 → ... - branch to TARGET if value A is not zero @@ -586,18 +615,20 @@ The `bnz` instruction opcode 0x40 is followed by two immediate data bytes which At v2 it became allowed to branch to the end of the program exactly after the last instruction: bnz to byte N (with 0-indexing) was illegal for a TEAL program with N bytes before v2, and is legal after it. This change eliminates the need for a last instruction of no-op as a branch target at the end. (Branching beyond the end--in other words, to a byte larger than N--is still illegal and will cause the program to fail.) -## bz target +## bz -- Opcode: 0x41 {int16 branch offset, big-endian} +- Syntax: `bz TARGET` ∋ TARGET: branch offset +- Bytecode: 0x41 {int16 (big-endian)} - Stack: ..., A: uint64 → ... - branch to TARGET if value A is zero - Availability: v2 See `bnz` for details on how branches work. `bz` inverts the behavior of `bnz`. -## b target +## b -- Opcode: 0x42 {int16 branch offset, big-endian} +- Syntax: `b TARGET` ∋ TARGET: branch offset +- Bytecode: 0x42 {int16 (big-endian)} - Stack: ... → ... - branch unconditionally to TARGET - Availability: v2 @@ -606,119 +637,126 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## return -- Opcode: 0x43 +- Bytecode: 0x43 - Stack: ..., A: uint64 → _exits_ - use A as success value; end - Availability: v2 ## assert -- Opcode: 0x44 +- Bytecode: 0x44 - Stack: ..., A: uint64 → ... - immediately fail unless A is a non-zero number - Availability: v3 -## bury n +## bury -- Opcode: 0x45 {uint8 depth} +- Syntax: `bury N` ∋ N: depth +- Bytecode: 0x45 {uint8} - Stack: ..., A → ... - replace the Nth value from the top of the stack with A. bury 0 fails. - Availability: v8 -## popn n +## popn -- Opcode: 0x46 {uint8 stack depth} +- Syntax: `popn N` ∋ N: stack depth +- Bytecode: 0x46 {uint8} - Stack: ..., [N items] → ... - remove N values from the top of the stack - Availability: v8 -## dupn n +## dupn -- Opcode: 0x47 {uint8 copy count} +- Syntax: `dupn N` ∋ N: copy count +- Bytecode: 0x47 {uint8} - Stack: ..., A → ..., A, [N copies of A] - duplicate A, N times - Availability: v8 ## pop -- Opcode: 0x48 +- Bytecode: 0x48 - Stack: ..., A → ... - discard A ## dup -- Opcode: 0x49 +- Bytecode: 0x49 - Stack: ..., A → ..., A, A - duplicate A ## dup2 -- Opcode: 0x4a +- Bytecode: 0x4a - Stack: ..., A, B → ..., A, B, A, B - duplicate A and B - Availability: v2 -## dig n +## dig -- Opcode: 0x4b {uint8 depth} +- Syntax: `dig N` ∋ N: depth +- Bytecode: 0x4b {uint8} - Stack: ..., A, [N items] → ..., A, [N items], A - Nth value from the top of the stack. dig 0 is equivalent to dup - Availability: v3 ## swap -- Opcode: 0x4c +- Bytecode: 0x4c - Stack: ..., A, B → ..., B, A - swaps A and B on stack - Availability: v3 ## select -- Opcode: 0x4d +- Bytecode: 0x4d - Stack: ..., A, B, C: uint64 → ..., A or B - selects one of two values based on top-of-stack: B if C != 0, else A - Availability: v3 -## cover n +## cover -- Opcode: 0x4e {uint8 depth} +- Syntax: `cover N` ∋ N: depth +- Bytecode: 0x4e {uint8} - Stack: ..., [N items], A → ..., A, [N items] - remove top of stack, and place it deeper in the stack such that N elements are above it. Fails if stack depth <= N. - Availability: v5 -## uncover n +## uncover -- Opcode: 0x4f {uint8 depth} +- Syntax: `uncover N` ∋ N: depth +- Bytecode: 0x4f {uint8} - Stack: ..., A, [N items] → ..., [N items], A - remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack. Fails if stack depth <= N. - Availability: v5 ## concat -- Opcode: 0x50 +- Bytecode: 0x50 - Stack: ..., A: []byte, B: []byte → ..., []byte - join A and B - Availability: v2 `concat` fails if the result would be greater than 4096 bytes. -## substring s e +## substring -- Opcode: 0x51 {uint8 start position} {uint8 end position} +- Syntax: `substring S E` ∋ S: start position, E: end position +- Bytecode: 0x51 {uint8}, {uint8} - Stack: ..., A: []byte → ..., []byte - A range of bytes from A starting at S up to but not including E. If E < S, or either is larger than the array length, the program fails - Availability: v2 ## substring3 -- Opcode: 0x52 +- Bytecode: 0x52 - Stack: ..., A: []byte, B: uint64, C: uint64 → ..., []byte - A range of bytes from A starting at B up to but not including C. If C < B, or either is larger than the array length, the program fails - Availability: v2 ## getbit -- Opcode: 0x53 +- Bytecode: 0x53 - Stack: ..., A, B: uint64 → ..., uint64 - Bth bit of (byte-array or integer) A. If B is greater than or equal to the bit length of the value (8*byte length), the program fails - Availability: v3 @@ -727,7 +765,7 @@ see explanation of bit ordering in setbit ## setbit -- Opcode: 0x54 +- Bytecode: 0x54 - Stack: ..., A, B: uint64, C: uint64 → ..., any - Copy of (byte-array or integer) A, with the Bth bit set to (0 or 1) C. If B is greater than or equal to the bit length of the value (8*byte length), the program fails - Availability: v3 @@ -736,76 +774,81 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on ## getbyte -- Opcode: 0x55 +- Bytecode: 0x55 - Stack: ..., A: []byte, B: uint64 → ..., uint64 - Bth byte of A, as an integer. If B is greater than or equal to the array length, the program fails - Availability: v3 ## setbyte -- Opcode: 0x56 +- Bytecode: 0x56 - Stack: ..., A: []byte, B: uint64, C: uint64 → ..., []byte - Copy of A with the Bth byte set to small integer (between 0..255) C. If B is greater than or equal to the array length, the program fails - Availability: v3 -## extract s l +## extract -- Opcode: 0x57 {uint8 start position} {uint8 length} +- Syntax: `extract S L` ∋ S: start position, L: length +- Bytecode: 0x57 {uint8}, {uint8} - Stack: ..., A: []byte → ..., []byte - A range of bytes from A starting at S up to but not including S+L. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails - Availability: v5 ## extract3 -- Opcode: 0x58 +- Bytecode: 0x58 - Stack: ..., A: []byte, B: uint64, C: uint64 → ..., []byte - A range of bytes from A starting at B up to but not including B+C. If B+C is larger than the array length, the program fails
`extract3` can be called using `extract` with no immediates. - Availability: v5 ## extract_uint16 -- Opcode: 0x59 +- Bytecode: 0x59 - Stack: ..., A: []byte, B: uint64 → ..., uint64 - A uint16 formed from a range of big-endian bytes from A starting at B up to but not including B+2. If B+2 is larger than the array length, the program fails - Availability: v5 ## extract_uint32 -- Opcode: 0x5a +- Bytecode: 0x5a - Stack: ..., A: []byte, B: uint64 → ..., uint64 - A uint32 formed from a range of big-endian bytes from A starting at B up to but not including B+4. If B+4 is larger than the array length, the program fails - Availability: v5 ## extract_uint64 -- Opcode: 0x5b +- Bytecode: 0x5b - Stack: ..., A: []byte, B: uint64 → ..., uint64 - A uint64 formed from a range of big-endian bytes from A starting at B up to but not including B+8. If B+8 is larger than the array length, the program fails - Availability: v5 -## replace2 s +## replace2 -- Opcode: 0x5c {uint8 start position} +- Syntax: `replace2 S` ∋ S: start position +- Bytecode: 0x5c {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - Copy of A with the bytes starting at S replaced by the bytes of B. Fails if S+len(B) exceeds len(A)
`replace2` can be called using `replace` with 1 immediate. - Availability: v7 ## replace3 -- Opcode: 0x5d +- Bytecode: 0x5d - Stack: ..., A: []byte, B: uint64, C: []byte → ..., []byte - Copy of A with the bytes starting at B replaced by the bytes of C. Fails if B+len(C) exceeds len(A)
`replace3` can be called using `replace` with no immediates. - Availability: v7 -## base64_decode e +## base64_decode -- Opcode: 0x5e {uint8 encoding index} +- Syntax: `base64_decode E` ∋ E: [base64](#field-group-base64) +- Bytecode: 0x5e {uint8} - Stack: ..., A: []byte → ..., []byte - decode A which was base64-encoded using _encoding_ E. Fail if A is not base64 encoded with encoding E - **Cost**: 1 + 1 per 16 bytes of A - Availability: v7 -`base64` Encodings: +### base64 + +Encodings | Index | Name | Notes | | - | ------ | --------- | @@ -817,15 +860,18 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on Decodes A using the base64 encoding E. Specify the encoding with an immediate arg either as URL and Filename Safe (`URLEncoding`) or Standard (`StdEncoding`). See [RFC 4648 sections 4 and 5](https://rfc-editor.org/rfc/rfc4648.html#section-4). It is assumed that the encoding ends with the exact number of `=` padding characters as required by the RFC. When padding occurs, any unused pad bits in the encoding must be set to zero or the decoding will fail. The special cases of `\n` and `\r` are allowed but completely ignored. An error will result when attempting to decode a string with a character that is not in the encoding alphabet or not one of `=`, `\r`, or `\n`. -## json_ref r +## json_ref -- Opcode: 0x5f {uint8 return type index} +- Syntax: `json_ref R` ∋ R: [json_ref](#field-group-json_ref) +- Bytecode: 0x5f {uint8} - Stack: ..., A: []byte, B: []byte → ..., any - key B's value, of type R, from a [valid](jsonspec.md) utf-8 encoded json object A - **Cost**: 25 + 2 per 7 bytes of A - Availability: v7 -`json_ref` Types: +### json_ref + +Types | Index | Name | Type | Notes | | - | ------ | -- | --------- | @@ -840,7 +886,7 @@ Almost all smart contracts should use simpler and smaller methods (such as the [ ## balance -- Opcode: 0x60 +- Bytecode: 0x60 - Stack: ..., A → ..., uint64 - balance for account A, in microalgos. The balance is observed after the effects of previous transactions in the group, and after the fee for the current transaction is deducted. Changes caused by inner transactions are observable immediately following `itxn_submit` - Availability: v2 @@ -850,8 +896,8 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address). Retu ## app_opted_in -- Opcode: 0x61 -- Stack: ..., A, B: uint64 → ..., uint64 +- Bytecode: 0x61 +- Stack: ..., A, B: uint64 → ..., bool - 1 if account A is opted in to application B, else 0 - Availability: v2 - Mode: Application @@ -860,7 +906,7 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address), _ava ## app_local_get -- Opcode: 0x62 +- Bytecode: 0x62 - Stack: ..., A, B: []byte → ..., any - local state of the key B in the current application in account A - Availability: v2 @@ -870,8 +916,8 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address), stat ## app_local_get_ex -- Opcode: 0x63 -- Stack: ..., A, B: uint64, C: []byte → ..., X: any, Y: uint64 +- Bytecode: 0x63 +- Stack: ..., A, B: uint64, C: []byte → ..., X: any, Y: bool - X is the local state of application B, key C in account A. Y is 1 if key existed, else 0 - Availability: v2 - Mode: Application @@ -880,7 +926,7 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address), _ava ## app_global_get -- Opcode: 0x64 +- Bytecode: 0x64 - Stack: ..., A: []byte → ..., any - global state of the key A in the current application - Availability: v2 @@ -890,8 +936,8 @@ params: state key. Return: value. The value is zero (of type uint64) if the key ## app_global_get_ex -- Opcode: 0x65 -- Stack: ..., A: uint64, B: []byte → ..., X: any, Y: uint64 +- Bytecode: 0x65 +- Stack: ..., A: uint64, B: []byte → ..., X: any, Y: bool - X is the global state of application A, key B. Y is 1 if key existed, else 0 - Availability: v2 - Mode: Application @@ -900,7 +946,7 @@ params: Txn.ForeignApps offset (or, since v4, an _available_ application id), st ## app_local_put -- Opcode: 0x66 +- Bytecode: 0x66 - Stack: ..., A, B: []byte, C → ... - write C to key B in account A's local state of the current application - Availability: v2 @@ -910,7 +956,7 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address), stat ## app_global_put -- Opcode: 0x67 +- Bytecode: 0x67 - Stack: ..., A: []byte, B → ... - write B to key A in the global state of the current application - Availability: v2 @@ -918,7 +964,7 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address), stat ## app_local_del -- Opcode: 0x68 +- Bytecode: 0x68 - Stack: ..., A, B: []byte → ... - delete key B from account A's local state of the current application - Availability: v2 @@ -930,7 +976,7 @@ Deleting a key which is already absent has no effect on the application local st ## app_global_del -- Opcode: 0x69 +- Bytecode: 0x69 - Stack: ..., A: []byte → ... - delete key A from the global state of the current application - Availability: v2 @@ -940,61 +986,70 @@ params: state key. Deleting a key which is already absent has no effect on the application global state. (In particular, it does _not_ cause the program to fail.) -## asset_holding_get f +## asset_holding_get -- Opcode: 0x70 {uint8 asset holding field index} -- Stack: ..., A, B: uint64 → ..., X: any, Y: uint64 +- Syntax: `asset_holding_get F` ∋ F: [asset_holding](#field-group-asset_holding) +- Bytecode: 0x70 {uint8} +- Stack: ..., A, B: uint64 → ..., X: any, Y: bool - X is field F from account A's holding of asset B. Y is 1 if A is opted into B, else 0 - Availability: v2 - Mode: Application -`asset_holding` Fields: +### asset_holding + +Fields | Index | Name | Type | Notes | | - | ------ | -- | --------- | | 0 | AssetBalance | uint64 | Amount of the asset unit held by this account | -| 1 | AssetFrozen | uint64 | Is the asset frozen or not | +| 1 | AssetFrozen | bool | Is the asset frozen or not | params: Txn.Accounts offset (or, since v4, an _available_ address), asset id (or, since v4, a Txn.ForeignAssets offset). Return: did_exist flag (1 if the asset existed and 0 otherwise), value. -## asset_params_get f +## asset_params_get -- Opcode: 0x71 {uint8 asset params field index} -- Stack: ..., A: uint64 → ..., X: any, Y: uint64 +- Syntax: `asset_params_get F` ∋ F: [asset_params](#field-group-asset_params) +- Bytecode: 0x71 {uint8} +- Stack: ..., A: uint64 → ..., X: any, Y: bool - X is field F from asset A. Y is 1 if A exists, else 0 - Availability: v2 - Mode: Application -`asset_params` Fields: +### asset_params + +Fields | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | | 0 | AssetTotal | uint64 | | Total number of units of this asset | | 1 | AssetDecimals | uint64 | | See AssetParams.Decimals | -| 2 | AssetDefaultFrozen | uint64 | | Frozen by default or not | +| 2 | AssetDefaultFrozen | bool | | Frozen by default or not | | 3 | AssetUnitName | []byte | | Asset unit name | | 4 | AssetName | []byte | | Asset name | | 5 | AssetURL | []byte | | URL with additional info about the asset | -| 6 | AssetMetadataHash | []byte | | Arbitrary commitment | -| 7 | AssetManager | []byte | | Manager address | -| 8 | AssetReserve | []byte | | Reserve address | -| 9 | AssetFreeze | []byte | | Freeze address | -| 10 | AssetClawback | []byte | | Clawback address | -| 11 | AssetCreator | []byte | v5 | Creator address | +| 6 | AssetMetadataHash | [32]byte | | Arbitrary commitment | +| 7 | AssetManager | address | | Manager address | +| 8 | AssetReserve | address | | Reserve address | +| 9 | AssetFreeze | address | | Freeze address | +| 10 | AssetClawback | address | | Clawback address | +| 11 | AssetCreator | address | v5 | Creator address | params: Txn.ForeignAssets offset (or, since v4, an _available_ asset id. Return: did_exist flag (1 if the asset existed and 0 otherwise), value. -## app_params_get f +## app_params_get -- Opcode: 0x72 {uint8 app params field index} -- Stack: ..., A: uint64 → ..., X: any, Y: uint64 +- Syntax: `app_params_get F` ∋ F: [app_params](#field-group-app_params) +- Bytecode: 0x72 {uint8} +- Stack: ..., A: uint64 → ..., X: any, Y: bool - X is field F from app A. Y is 1 if A exists, else 0 - Availability: v5 - Mode: Application -`app_params` Fields: +### app_params + +Fields | Index | Name | Type | Notes | | - | ------ | -- | --------- | @@ -1005,27 +1060,30 @@ params: Txn.ForeignAssets offset (or, since v4, an _available_ asset id. Return: | 4 | AppLocalNumUint | uint64 | Number of uint64 values allowed in Local State | | 5 | AppLocalNumByteSlice | uint64 | Number of byte array values allowed in Local State | | 6 | AppExtraProgramPages | uint64 | Number of Extra Program Pages of code space | -| 7 | AppCreator | []byte | Creator address | -| 8 | AppAddress | []byte | Address for which this application has authority | +| 7 | AppCreator | address | Creator address | +| 8 | AppAddress | address | Address for which this application has authority | params: Txn.ForeignApps offset or an _available_ app id. Return: did_exist flag (1 if the application existed and 0 otherwise), value. -## acct_params_get f +## acct_params_get -- Opcode: 0x73 {uint8 account params field index} -- Stack: ..., A → ..., X: any, Y: uint64 +- Syntax: `acct_params_get F` ∋ F: [acct_params](#field-group-acct_params) +- Bytecode: 0x73 {uint8} +- Stack: ..., A → ..., X: any, Y: bool - X is field F from account A. Y is 1 if A owns positive algos, else 0 - Availability: v6 - Mode: Application -`acct_params` Fields: +### acct_params + +Fields | Index | Name | Type | In | Notes | | - | ------ | -- | - | --------- | | 0 | AcctBalance | uint64 | | Account balance in microalgos | | 1 | AcctMinBalance | uint64 | | Minimum required balance for account, in microalgos | -| 2 | AcctAuthAddr | []byte | | Address the account is rekeyed to. | +| 2 | AcctAuthAddr | address | | Address the account is rekeyed to. | | 3 | AcctTotalNumUint | uint64 | v8 | The total number of uint64 values allocated by this account in Global and Local States. | | 4 | AcctTotalNumByteSlice | uint64 | v8 | The total number of byte array values allocated by this account in Global and Local States. | | 5 | AcctTotalExtraAppPages | uint64 | v8 | The number of extra app code pages used by this account. | @@ -1039,7 +1097,7 @@ params: Txn.ForeignApps offset or an _available_ app id. Return: did_exist flag ## min_balance -- Opcode: 0x78 +- Bytecode: 0x78 - Stack: ..., A → ..., uint64 - minimum required balance for account A, in microalgos. Required balance is affected by ASA, App, and Box usage. When creating or opting into an app, the minimum balance grows before the app code runs, therefore the increase is visible there. When deleting or closing out, the minimum balance decreases after the app executes. Changes caused by inner transactions or box usage are observable immediately following the opcode effecting the change. - Availability: v3 @@ -1047,36 +1105,40 @@ params: Txn.ForeignApps offset or an _available_ app id. Return: did_exist flag params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value. -## pushbytes bytes +## pushbytes -- Opcode: 0x80 {varuint length} {bytes} +- Syntax: `pushbytes BYTES` ∋ BYTES: a byte constant +- Bytecode: 0x80 {varuint length, bytes} - Stack: ... → ..., []byte - immediate BYTES - Availability: v3 pushbytes args are not added to the bytecblock during assembly processes -## pushint uint +## pushint -- Opcode: 0x81 {varuint int} +- Syntax: `pushint UINT` ∋ UINT: an int constant +- Bytecode: 0x81 {varuint} - Stack: ... → ..., uint64 - immediate UINT - Availability: v3 pushint args are not added to the intcblock during assembly processes -## pushbytess bytes ... +## pushbytess -- Opcode: 0x82 {varuint count} [({varuint length} bytes), ...] +- Syntax: `pushbytess BYTES ...` ∋ BYTES ...: a list of byte constants +- Bytecode: 0x82 {varuint count, [varuint length, bytes ...]} - Stack: ... → ..., [N items] - push sequences of immediate byte arrays to stack (first byte array being deepest) - Availability: v8 pushbytess args are not added to the bytecblock during assembly processes -## pushints uint ... +## pushints -- Opcode: 0x83 {varuint count} [{varuint value}, ...] +- Syntax: `pushints UINT ...` ∋ UINT ...: a list of int constants +- Bytecode: 0x83 {varuint count, [varuint ...]} - Stack: ... → ..., [N items] - push sequence of immediate uints to stack in the order they appear (first uint being deepest) - Availability: v8 @@ -1085,15 +1147,16 @@ pushints args are not added to the intcblock during assembly processes ## ed25519verify_bare -- Opcode: 0x84 -- Stack: ..., A: []byte, B: []byte, C: []byte → ..., uint64 +- Bytecode: 0x84 +- Stack: ..., A: []byte, B: []byte, C: []byte → ..., bool - for (data A, signature B, pubkey C) verify the signature of the data against the pubkey => {0 or 1} - **Cost**: 1900 - Availability: v7 -## callsub target +## callsub -- Opcode: 0x88 {int16 branch offset, big-endian} +- Syntax: `callsub TARGET` ∋ TARGET: branch offset +- Bytecode: 0x88 {int16 (big-endian)} - Stack: ... → ... - branch unconditionally to TARGET, saving the next instruction on the call stack - Availability: v4 @@ -1102,46 +1165,51 @@ The call stack is separate from the data stack. Only `callsub`, `retsub`, and `p ## retsub -- Opcode: 0x89 +- Bytecode: 0x89 - Stack: ... → ... - pop the top instruction from the call stack and branch to it - Availability: v4 If the current frame was prepared by `proto A R`, `retsub` will remove the 'A' arguments from the stack, move the `R` return values down, and pop any stack locations above the relocated return values. -## proto a r +## proto -- Opcode: 0x8a {uint8 arguments} {uint8 return values} +- Syntax: `proto A R` ∋ A: number of arguments, R: number of return values +- Bytecode: 0x8a {uint8}, {uint8} - Stack: ... → ... - Prepare top call frame for a retsub that will assume A args and R return values. - Availability: v8 Fails unless the last instruction executed was a `callsub`. -## frame_dig i +## frame_dig -- Opcode: 0x8b {int8 frame slot} +- Syntax: `frame_dig I` ∋ I: frame slot +- Bytecode: 0x8b {int8} - Stack: ... → ..., any - Nth (signed) value from the frame pointer. - Availability: v8 -## frame_bury i +## frame_bury -- Opcode: 0x8c {int8 frame slot} +- Syntax: `frame_bury I` ∋ I: frame slot +- Bytecode: 0x8c {int8} - Stack: ..., A → ... - replace the Nth (signed) value from the frame pointer in the stack with A - Availability: v8 -## switch target ... +## switch -- Opcode: 0x8d {uint8 branch count} [{int16 branch offset, big-endian}, ...] +- Syntax: `switch TARGET ...` ∋ TARGET ...: list of labels +- Bytecode: 0x8d {varuint count, [int16 (big-endian) ...]} - Stack: ..., A: uint64 → ... - branch to the Ath label. Continue at following instruction if index A exceeds the number of labels. - Availability: v8 -## match target ... +## match -- Opcode: 0x8e {uint8 branch count} [{int16 branch offset, big-endian}, ...] +- Syntax: `match TARGET ...` ∋ TARGET ...: list of labels +- Bytecode: 0x8e {varuint count, [int16 (big-endian) ...]} - Stack: ..., [A1, A2, ..., AN], B → ... - given match cases from A[1] to A[N], branch to the Ith label where A[I] = B. Continue to the following instruction if no matches are found. - Availability: v8 @@ -1150,21 +1218,21 @@ Fails unless the last instruction executed was a `callsub`. ## shl -- Opcode: 0x90 +- Bytecode: 0x90 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A times 2^B, modulo 2^64 - Availability: v4 ## shr -- Opcode: 0x91 +- Bytecode: 0x91 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A divided by 2^B - Availability: v4 ## sqrt -- Opcode: 0x92 +- Bytecode: 0x92 - Stack: ..., A: uint64 → ..., uint64 - The largest integer I such that I^2 <= A - **Cost**: 4 @@ -1172,7 +1240,7 @@ Fails unless the last instruction executed was a `callsub`. ## bitlen -- Opcode: 0x93 +- Bytecode: 0x93 - Stack: ..., A → ..., uint64 - The highest set bit in A. If A is a byte-array, it is interpreted as a big-endian unsigned integer. bitlen of 0 is 0, bitlen of 8 is 4 - Availability: v4 @@ -1181,14 +1249,14 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit ## exp -- Opcode: 0x94 +- Bytecode: 0x94 - Stack: ..., A: uint64, B: uint64 → ..., uint64 - A raised to the Bth power. Fail if A == B == 0 and on overflow - Availability: v4 ## expw -- Opcode: 0x95 +- Bytecode: 0x95 - Stack: ..., A: uint64, B: uint64 → ..., X: uint64, Y: uint64 - A raised to the Bth power as a 128-bit result in two uint64s. X is the high 64 bits, Y is the low. Fail if A == B == 0 or if the results exceeds 2^128-1 - **Cost**: 10 @@ -1196,7 +1264,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit ## bsqrt -- Opcode: 0x96 +- Bytecode: 0x96 - Stack: ..., A: []byte → ..., []byte - The largest integer I such that I^2 <= A. A and I are interpreted as big-endian unsigned integers - **Cost**: 40 @@ -1204,7 +1272,7 @@ bitlen interprets arrays as big-endian integers, unlike setbit/getbit ## divw -- Opcode: 0x97 +- Bytecode: 0x97 - Stack: ..., A: uint64, B: uint64, C: uint64 → ..., uint64 - A,B / C. Fail if C == 0 or if result overflows. - Availability: v6 @@ -1213,7 +1281,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## sha3_256 -- Opcode: 0x98 +- Bytecode: 0x98 - Stack: ..., A: []byte → ..., []byte - SHA3_256 hash of value A, yields [32]byte - **Cost**: 130 @@ -1221,81 +1289,81 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## b+ -- Opcode: 0xa0 -- Stack: ..., A: []byte, B: []byte → ..., []byte +- Bytecode: 0xa0 +- Stack: ..., A: bigint, B: bigint → ..., []byte - A plus B. A and B are interpreted as big-endian unsigned integers - **Cost**: 10 - Availability: v4 ## b- -- Opcode: 0xa1 -- Stack: ..., A: []byte, B: []byte → ..., []byte +- Bytecode: 0xa1 +- Stack: ..., A: bigint, B: bigint → ..., bigint - A minus B. A and B are interpreted as big-endian unsigned integers. Fail on underflow. - **Cost**: 10 - Availability: v4 ## b/ -- Opcode: 0xa2 -- Stack: ..., A: []byte, B: []byte → ..., []byte +- Bytecode: 0xa2 +- Stack: ..., A: bigint, B: bigint → ..., bigint - A divided by B (truncated division). A and B are interpreted as big-endian unsigned integers. Fail if B is zero. - **Cost**: 20 - Availability: v4 ## b* -- Opcode: 0xa3 -- Stack: ..., A: []byte, B: []byte → ..., []byte +- Bytecode: 0xa3 +- Stack: ..., A: bigint, B: bigint → ..., []byte - A times B. A and B are interpreted as big-endian unsigned integers. - **Cost**: 20 - Availability: v4 ## b< -- Opcode: 0xa4 -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Bytecode: 0xa4 +- Stack: ..., A: bigint, B: bigint → ..., bool - 1 if A is less than B, else 0. A and B are interpreted as big-endian unsigned integers - Availability: v4 ## b> -- Opcode: 0xa5 -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Bytecode: 0xa5 +- Stack: ..., A: bigint, B: bigint → ..., bool - 1 if A is greater than B, else 0. A and B are interpreted as big-endian unsigned integers - Availability: v4 ## b<= -- Opcode: 0xa6 -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Bytecode: 0xa6 +- Stack: ..., A: bigint, B: bigint → ..., bool - 1 if A is less than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers - Availability: v4 ## b>= -- Opcode: 0xa7 -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Bytecode: 0xa7 +- Stack: ..., A: bigint, B: bigint → ..., bool - 1 if A is greater than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers - Availability: v4 ## b== -- Opcode: 0xa8 -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Bytecode: 0xa8 +- Stack: ..., A: bigint, B: bigint → ..., bool - 1 if A is equal to B, else 0. A and B are interpreted as big-endian unsigned integers - Availability: v4 ## b!= -- Opcode: 0xa9 -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Bytecode: 0xa9 +- Stack: ..., A: bigint, B: bigint → ..., bool - 0 if A is equal to B, else 1. A and B are interpreted as big-endian unsigned integers - Availability: v4 ## b% -- Opcode: 0xaa +- Bytecode: 0xaa - Stack: ..., A: []byte, B: []byte → ..., []byte - A modulo B. A and B are interpreted as big-endian unsigned integers. Fail if B is zero. - **Cost**: 20 @@ -1303,7 +1371,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## b| -- Opcode: 0xab +- Bytecode: 0xab - Stack: ..., A: []byte, B: []byte → ..., []byte - A bitwise-or B. A and B are zero-left extended to the greater of their lengths - **Cost**: 6 @@ -1311,7 +1379,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## b& -- Opcode: 0xac +- Bytecode: 0xac - Stack: ..., A: []byte, B: []byte → ..., []byte - A bitwise-and B. A and B are zero-left extended to the greater of their lengths - **Cost**: 6 @@ -1319,7 +1387,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## b^ -- Opcode: 0xad +- Bytecode: 0xad - Stack: ..., A: []byte, B: []byte → ..., []byte - A bitwise-xor B. A and B are zero-left extended to the greater of their lengths - **Cost**: 6 @@ -1327,7 +1395,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## b~ -- Opcode: 0xae +- Bytecode: 0xae - Stack: ..., A: []byte → ..., []byte - A with all bits inverted - **Cost**: 4 @@ -1335,14 +1403,14 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## bzero -- Opcode: 0xaf +- Bytecode: 0xaf - Stack: ..., A: uint64 → ..., []byte - zero filled byte-array of length A - Availability: v4 ## log -- Opcode: 0xb0 +- Bytecode: 0xb0 - Stack: ..., A: []byte → ... - write A to log state of the current application - Availability: v5 @@ -1352,7 +1420,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## itxn_begin -- Opcode: 0xb1 +- Bytecode: 0xb1 - Stack: ... → ... - begin preparation of a new inner transaction in a new transaction group - Availability: v5 @@ -1360,9 +1428,10 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with `itxn_begin` initializes Sender to the application address; Fee to the minimum allowable, taking into account MinTxnFee and credit from overpaying in earlier transactions; FirstValid/LastValid to the values in the invoking transaction, and all other fields to zero or empty values. -## itxn_field f +## itxn_field -- Opcode: 0xb2 {uint8 transaction field index} +- Syntax: `itxn_field F` ∋ F: [txn](#field-group-txn) +- Bytecode: 0xb2 {uint8} - Stack: ..., A → ... - set field F of the current inner transaction to A - Availability: v5 @@ -1372,7 +1441,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## itxn_submit -- Opcode: 0xb3 +- Bytecode: 0xb3 - Stack: ... → ... - execute the current inner transaction group. Fail if executing this group would exceed the inner transaction limit, or if any transaction in the group fails. - Availability: v5 @@ -1380,17 +1449,19 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with `itxn_submit` resets the current transaction so that it can not be resubmitted. A new `itxn_begin` is required to prepare another inner transaction. -## itxn f +## itxn -- Opcode: 0xb4 {uint8 transaction field index} +- Syntax: `itxn F` ∋ F: [txn](#field-group-txn) +- Bytecode: 0xb4 {uint8} - Stack: ... → ..., any - field F of the last inner transaction - Availability: v5 - Mode: Application -## itxna f i +## itxna -- Opcode: 0xb5 {uint8 transaction field index} {uint8 transaction field array index} +- Syntax: `itxna F I` ∋ F: [txna](#field-group-txna), I: a transaction field array index +- Bytecode: 0xb5 {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F of the last inner transaction - Availability: v5 @@ -1398,7 +1469,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## itxn_next -- Opcode: 0xb6 +- Bytecode: 0xb6 - Stack: ... → ... - begin preparation of a new inner transaction in the same transaction group - Availability: v6 @@ -1406,17 +1477,19 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with `itxn_next` initializes the transaction exactly as `itxn_begin` does -## gitxn t f +## gitxn -- Opcode: 0xb7 {uint8 transaction group index} {uint8 transaction field index} +- Syntax: `gitxn T F` ∋ T: transaction group index, F: [txn](#field-group-txn) +- Bytecode: 0xb7 {uint8}, {uint8} - Stack: ... → ..., any - field F of the Tth transaction in the last inner group submitted - Availability: v6 - Mode: Application -## gitxna t f i +## gitxna -- Opcode: 0xb8 {uint8 transaction group index} {uint8 transaction field index} {uint8 transaction field array index} +- Syntax: `gitxna T F I` ∋ T: transaction group index, F: [txna](#field-group-txna), I: transaction field array index +- Bytecode: 0xb8 {uint8}, {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F from the Tth transaction in the last inner group submitted - Availability: v6 @@ -1424,8 +1497,8 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## box_create -- Opcode: 0xb9 -- Stack: ..., A: []byte, B: uint64 → ..., uint64 +- Bytecode: 0xb9 +- Stack: ..., A: boxName, B: uint64 → ..., bool - create a box named A, of length B. Fail if A is empty or B exceeds 32,768. Returns 0 if A already existed, else 1 - Availability: v8 - Mode: Application @@ -1434,40 +1507,40 @@ Newly created boxes are filled with 0 bytes. `box_create` will fail if the refer ## box_extract -- Opcode: 0xba -- Stack: ..., A: []byte, B: uint64, C: uint64 → ..., []byte +- Bytecode: 0xba +- Stack: ..., A: boxName, B: uint64, C: uint64 → ..., []byte - read C bytes from box A, starting at offset B. Fail if A does not exist, or the byte range is outside A's size. - Availability: v8 - Mode: Application ## box_replace -- Opcode: 0xbb -- Stack: ..., A: []byte, B: uint64, C: []byte → ... +- Bytecode: 0xbb +- Stack: ..., A: boxName, B: uint64, C: []byte → ... - write byte-array C into box A, starting at offset B. Fail if A does not exist, or the byte range is outside A's size. - Availability: v8 - Mode: Application ## box_del -- Opcode: 0xbc -- Stack: ..., A: []byte → ..., uint64 +- Bytecode: 0xbc +- Stack: ..., A: boxName → ..., bool - delete box named A if it exists. Return 1 if A existed, 0 otherwise - Availability: v8 - Mode: Application ## box_len -- Opcode: 0xbd -- Stack: ..., A: []byte → ..., X: uint64, Y: uint64 +- Bytecode: 0xbd +- Stack: ..., A: boxName → ..., X: uint64, Y: bool - X is the length of box A if A exists, else 0. Y is 1 if A exists, else 0. - Availability: v8 - Mode: Application ## box_get -- Opcode: 0xbe -- Stack: ..., A: []byte → ..., X: []byte, Y: uint64 +- Bytecode: 0xbe +- Stack: ..., A: boxName → ..., X: []byte, Y: bool - X is the contents of box A if A exists, else ''. Y is 1 if A exists, else 0. - Availability: v8 - Mode: Application @@ -1476,38 +1549,41 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## box_put -- Opcode: 0xbf -- Stack: ..., A: []byte, B: []byte → ... +- Bytecode: 0xbf +- Stack: ..., A: boxName, B: []byte → ... - replaces the contents of box A with byte-array B. Fails if A exists and len(B) != len(box A). Creates A if it does not exist - Availability: v8 - Mode: Application For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `box_replace` -## txnas f +## txnas -- Opcode: 0xc0 {uint8 transaction field index} +- Syntax: `txnas F` ∋ F: [txna](#field-group-txna) +- Bytecode: 0xc0 {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F of the current transaction - Availability: v5 -## gtxnas t f +## gtxnas -- Opcode: 0xc1 {uint8 transaction group index} {uint8 transaction field index} +- Syntax: `gtxnas T F` ∋ T: transaction group index, F: [txna](#field-group-txna) +- Bytecode: 0xc1 {uint8}, {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F from the Tth transaction in the current group - Availability: v5 -## gtxnsas f +## gtxnsas -- Opcode: 0xc2 {uint8 transaction field index} +- Syntax: `gtxnsas F` ∋ F: [txna](#field-group-txna) +- Bytecode: 0xc2 {uint8} - Stack: ..., A: uint64, B: uint64 → ..., any - Bth value of the array field F from the Ath transaction in the current group - Availability: v5 ## args -- Opcode: 0xc3 +- Bytecode: 0xc3 - Stack: ..., A: uint64 → ..., []byte - Ath LogicSig argument - Availability: v5 @@ -1515,37 +1591,42 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## gloadss -- Opcode: 0xc4 +- Bytecode: 0xc4 - Stack: ..., A: uint64, B: uint64 → ..., any - Bth scratch space value of the Ath transaction in the current group - Availability: v6 - Mode: Application -## itxnas f +## itxnas -- Opcode: 0xc5 {uint8 transaction field index} +- Syntax: `itxnas F` ∋ F: [txna](#field-group-txna) +- Bytecode: 0xc5 {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F of the last inner transaction - Availability: v6 - Mode: Application -## gitxnas t f +## gitxnas -- Opcode: 0xc6 {uint8 transaction group index} {uint8 transaction field index} +- Syntax: `gitxnas T F` ∋ T: transaction group index, F: [txna](#field-group-txna) +- Bytecode: 0xc6 {uint8}, {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F from the Tth transaction in the last inner group submitted - Availability: v6 - Mode: Application -## vrf_verify s +## vrf_verify -- Opcode: 0xd0 {uint8 parameters index} -- Stack: ..., A: []byte, B: []byte, C: []byte → ..., X: []byte, Y: uint64 +- Syntax: `vrf_verify S` ∋ S: [vrf_verify](#field-group-vrf_verify) +- Bytecode: 0xd0 {uint8} +- Stack: ..., A: []byte, B: []byte, C: []byte → ..., X: []byte, Y: bool - Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. - **Cost**: 5700 - Availability: v7 -`vrf_verify` Standards: +### vrf_verify + +Standards | Index | Name | Notes | | - | ------ | --------- | @@ -1554,14 +1635,17 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo `VrfAlgorand` is the VRF used in Algorand. It is ECVRF-ED25519-SHA512-Elligator2, specified in the IETF internet draft [draft-irtf-cfrg-vrf-03](https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/03/). -## block f +## block -- Opcode: 0xd1 {uint8 block field index} +- Syntax: `block F` ∋ F: [block](#field-group-block) +- Bytecode: 0xd1 {uint8} - Stack: ..., A: uint64 → ..., any - field F of block A. Fail unless A falls between txn.LastValid-1002 and txn.FirstValid (exclusive) - Availability: v7 -`block` Fields: +### block + +Fields | Index | Name | Type | Notes | | - | ------ | -- | --------- | From 89ce0ccd148eb0d146d8f1f12c5ef109a205ba14 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Wed, 2 Aug 2023 11:19:47 -0400 Subject: [PATCH 2/8] ec specs --- dev/TEAL.md | 51 ++++++++++++------------ dev/TEAL_opcodes.md | 95 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 115 insertions(+), 31 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index df57937..7578edc 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -130,21 +130,21 @@ A program can either authorize some delegated action on a normal signature-based or multisignature-based account or be wholly in charge of a contract account. -* *Delegated Smart Signatures* --- If the account has signed the - program (by providing a valid ed25519 signature or valid - multisignature for the authorizer address on the string "Program" - concatenated with the program bytecode) then: if the program returns - true the transaction is authorized as if the account had signed - it. This allows an account to hand out a signed program so that - other users can carry out delegated actions which are approved by - the program. Note that Smart Signature Args are _not_ signed. - -* *Contract Smart Signatures* -- If the SHA512_256 hash of the program - (prefixed by "Program") is equal to authorizer address of the - transaction sender then this is a contract account wholly controlled - by the program. No other signature is necessary or possible. The - only way to execute a transaction against the contract account is - for the program to approve it. +* If the account has signed the program (by providing a valid ed25519 + signature or valid multisignature for the authorizer address on the + string "Program" concatenated with the program bytecode) then: if the + program returns true the transaction is authorized as if the account + had signed it. This allows an account to hand out a signed program + so that other users can carry out delegated actions which are + approved by the program. Note that Smart Signature Args are _not_ + signed. + +* If the SHA512_256 hash of the program (prefixed by "Program") is + equal to authorizer address of the transaction sender then this is a + contract account wholly controlled by the program. No other + signature is necessary or possible. The only way to execute a + transaction against the contract account is for the program to + approve it. The bytecode plus the length of all Args must add up to no more than 1000 bytes (consensus parameter LogicSigMaxSize). Each opcode has an @@ -155,18 +155,9 @@ executed or not). Beginning with v4, the program's cost is tracked dynamically, while being evaluated. If the program exceeds its budget, it fails. -The total program cost of a _delegated_ Smart Signature program must -no exceed 20,000 (consensus parameter LogicSigMaxCost). - -The total program cost of all _contract_ signatures in a group must -not exceed 20,000 (consensus parameter LogicSigMaxCost) times the -number of transactions in the group that are not signed by delegated -Smart Signatures. - -More intuitively --- Delegated Smart Signatures receive 20,000 opcode -units, which they are free to use, but are not shared. All other -transactions receive 20,000 opcode units each, which are shared among -the Contract Smart Signatures. +The total program cost of all Smart Signatures in a group must not +exceed 20,000 (consensus parameter LogicSigMaxCost) times the number +of transactions in the group. ## Execution Environment for Smart Contracts (Applications) @@ -390,6 +381,12 @@ return stack matches the name of the input value. | `ecdsa_pk_recover v` | for (data A, recovery id B, signature C, D) recover a public key | | `ecdsa_pk_decompress v` | decompress pubkey A into components X, Y | | `vrf_verify s` | Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. | +| `ec_add g` | for curve points A and B, return the curve point A + B | +| `ec_scalar_mul g` | for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. | +| `ec_pairing_check g` | 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 | +| `ec_multi_exp g` | for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn | +| `ec_subgroup_check g` | 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. | +| `ec_map_to g` | maps field element A to group G | | `+` | A plus B. Fail on overflow. | | `-` | A minus B. Fail if B > A. | | `/` | A divided by B (truncated division). Fail if B == 0. | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 0807379..d36f72e 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -59,7 +59,7 @@ The 32 byte public key is the last element on the stack, preceded by the 64 byte - Bytecode: 0x05 {uint8} - Stack: ..., A: []byte, B: []byte, C: []byte, D: []byte, E: []byte → ..., bool - for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} -- **Cost**: Secp256k1=1700 Secp256r1=2500 +- **Cost**: Secp256k1=1700; Secp256r1=2500 - Availability: v5 ### ECDSA @@ -80,7 +80,7 @@ The 32 byte Y-component of a public key is the last element on the stack, preced - Bytecode: 0x06 {uint8} - Stack: ..., A: []byte → ..., X: []byte, Y: []byte - decompress pubkey A into components X, Y -- **Cost**: Secp256k1=650 Secp256r1=2400 +- **Cost**: Secp256k1=650; Secp256r1=2400 - Availability: v5 The 33 byte public key in a compressed form to be decompressed into X and Y (top) components. All values are big-endian encoded. @@ -892,7 +892,7 @@ Almost all smart contracts should use simpler and smaller methods (such as the [ - Availability: v2 - Mode: Application -params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value. +params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value. ## app_opted_in @@ -1103,7 +1103,7 @@ Fields - Availability: v3 - Mode: Application -params: Txn.Accounts offset (or, since v4, an _available_ account address). Return: value. +params: Txn.Accounts offset (or, since v4, an _available_ account address), _available_ application id (or, since v4, a Txn.ForeignApps offset). Return: value. ## pushbytes @@ -1652,3 +1652,90 @@ Fields | 0 | BlkSeed | []byte | | | 1 | BlkTimestamp | uint64 | | + +## ec_add + +- Syntax: `ec_add G` ∋ G: [EC](#field-group-ec) +- Bytecode: 0xe0 {uint8} +- Stack: ..., A: []byte, B: []byte → ..., []byte +- for curve points A and B, return the curve point A + B +- **Cost**: BN254g1=310; BN254g2=430; BLS12_381g1=540; BLS12_381g2=750 +- Availability: v10 + +### EC + +Groups + +| Index | Name | Notes | +| - | ------ | --------- | +| 0 | BN254g1 | G1 of the BN254 curve. Points encoded as 32 byte X following by 32 byte Y | +| 1 | BN254g2 | G2 of the BN254 curve. Points encoded as 64 byte X following by 64 byte Y | +| 2 | BLS12_381g1 | G1 of the BLS 12-381 curve. Points encoded as 48 byte X following by 48 byte Y | +| 3 | BLS12_381g2 | G2 of the BLS 12-381 curve. Points encoded as 96 byte X following by 48 byte Y | + + +A and B are curve points in affine representation: field element X concatenated with field element Y. Field element `Z` is encoded as follows. +For the base field elements (Fp), `Z` is encoded as a big-endian number and must be lower than the field modulus. +For the quadratic field extension (Fp2), `Z` is encoded as the concatenation of the individual encoding of the coefficients. For an Fp2 element of the form `Z = Z0 + Z1 i`, where `i` is a formal quadratic non-residue, the encoding of Z is the concatenation of the encoding of `Z0` and `Z1` in this order. (`Z0` and `Z1` must be less than the field modulus). + +The point at infinity is encoded as `(X,Y) = (0,0)`. +Groups G1 and G2 are denoted additively. + +Fails if A or B is not in G. +A and/or B are allowed to be the point at infinity. +Does _not_ check if A and B are in the main prime-order subgroup. + +## ec_scalar_mul + +- Syntax: `ec_scalar_mul G` ∋ G: [EC](#field-group-ec) +- Bytecode: 0xe1 {uint8} +- Stack: ..., A: []byte, B: []byte → ..., []byte +- for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. +- **Cost**: BN254g1=2200; BN254g2=4460; BLS12_381g1=3640; BLS12_381g2=8530 +- Availability: v10 + +A is a curve point encoded and checked as described in `ec_add`. Scalar B is interpreted as a big-endian unsigned integer. Fails if B exceeds 32 bytes. + +## ec_pairing_check + +- Syntax: `ec_pairing_check G` ∋ G: [EC](#field-group-ec) +- Bytecode: 0xe2 {uint8} +- Stack: ..., A: []byte, B: []byte → ..., uint64 +- 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 +- **Cost**: BN254g1=1 + 180 per 64 bytes of B; BN254g2=1 + 180 per 128 bytes of B; BLS12_381g1=450 + 400 per 96 bytes of B; BLS12_381g2=450 + 400 per 192 bytes of B +- Availability: v10 + +A and B are concatenated points, encoded and checked as described in `ec_add`. A contains points of the group G, B contains points of the associated group (G2 if G is G1, and vice versa). Fails if A and B have a different number of points, or if any point is not in its described group or outside the main prime-order subgroup - a stronger condition than other opcodes AVM values are limited to 4096 bytes, so `ec_pairing_check` is limited by the size of the points in the groups being operated upon. + +## ec_multi_exp + +- Syntax: `ec_multi_exp G` ∋ G: [EC](#field-group-ec) +- Bytecode: 0xe3 {uint8} +- Stack: ..., A: []byte, B: []byte → ..., []byte +- for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn +- **Cost**: BN254g1=80 + 3 per 32 bytes of B; BN254g2=180 + 9 per 32 bytes of B; BLS12_381g1=140 + 4 per 32 bytes of B; BLS12_381g2=350 + 18 per 32 bytes of B +- Availability: v10 + +A is a list of concatenated points, encoded and checked as described in `ec_add`. B is a list of concatenated scalars which, unlike ec_scalar_mul, must all be exactly 32 bytes long. +The name `ec_multi_exp` was chosen to reflect common usage, but a more consistent name would be `ec_multi_scalar_mul`. AVM values are limited to 4096 bytes, so `ec_multi_exp` is limited by the size of the points in the group being operated upon. + +## ec_subgroup_check + +- Syntax: `ec_subgroup_check G` ∋ G: [EC](#field-group-ec) +- Bytecode: 0xe4 {uint8} +- Stack: ..., A: []byte → ..., uint64 +- 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. +- **Cost**: BN254g1=50; BN254g2=11500; BLS12_381g1=5600; BLS12_381g2=7100 +- Availability: v10 + +## ec_map_to + +- Syntax: `ec_map_to G` ∋ G: [EC](#field-group-ec) +- Bytecode: 0xe5 {uint8} +- Stack: ..., A: []byte → ..., []byte +- maps field element A to group G +- **Cost**: BN254g1=1700; BN254g2=11000; BLS12_381g1=5600; BLS12_381g2=43000 +- Availability: v10 + +BN254 points are mapped by the SVDW map. BLS12-381 points are mapped by the SSWU map. +G1 element inputs are base field elements and G2 element inputs are quadratic field elements, with nearly the same encoding rules (for field elements) as defined in `ec_add`. There is one difference of encoding rule: G1 element inputs do not need to be 0-padded if they fit in less than 32 bytes for BN254 and less than 48 bytes for BLS12-381. (As usual, the empty byte array represents 0.) G2 elements inputs need to be always have the required size. From 51748fa0d70a05f81acc659fa038048a88872b6b Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 15 Aug 2023 10:27:03 -0400 Subject: [PATCH 3/8] rename ec_multi_exp to ec_multi_scalar_mul --- dev/TEAL_opcodes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index d36f72e..026b368 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1671,7 +1671,7 @@ Groups | 0 | BN254g1 | G1 of the BN254 curve. Points encoded as 32 byte X following by 32 byte Y | | 1 | BN254g2 | G2 of the BN254 curve. Points encoded as 64 byte X following by 64 byte Y | | 2 | BLS12_381g1 | G1 of the BLS 12-381 curve. Points encoded as 48 byte X following by 48 byte Y | -| 3 | BLS12_381g2 | G2 of the BLS 12-381 curve. Points encoded as 96 byte X following by 48 byte Y | +| 3 | BLS12_381g2 | G2 of the BLS 12-381 curve. Points encoded as 96 byte X following by 96 byte Y | A and B are curve points in affine representation: field element X concatenated with field element Y. Field element `Z` is encoded as follows. @@ -1702,22 +1702,22 @@ A is a curve point encoded and checked as described in `ec_add`. Scalar B is int - Bytecode: 0xe2 {uint8} - Stack: ..., A: []byte, B: []byte → ..., uint64 - 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 -- **Cost**: BN254g1=1 + 180 per 64 bytes of B; BN254g2=1 + 180 per 128 bytes of B; BLS12_381g1=450 + 400 per 96 bytes of B; BLS12_381g2=450 + 400 per 192 bytes of B +- **Cost**: BN254g1=1 + 18000 per 64 bytes of B; BN254g2=1 + 18000 per 128 bytes of B; BLS12_381g1=45000 + 40000 per 96 bytes of B; BLS12_381g2=45000 + 40000 per 192 bytes of B - Availability: v10 -A and B are concatenated points, encoded and checked as described in `ec_add`. A contains points of the group G, B contains points of the associated group (G2 if G is G1, and vice versa). Fails if A and B have a different number of points, or if any point is not in its described group or outside the main prime-order subgroup - a stronger condition than other opcodes AVM values are limited to 4096 bytes, so `ec_pairing_check` is limited by the size of the points in the groups being operated upon. +A and B are concatenated points, encoded and checked as described in `ec_add`. A contains points of the group G, B contains points of the associated group (G2 if G is G1, and vice versa). Fails if A and B have a different number of points, or if any point is not in its described group or outside the main prime-order subgroup - a stronger condition than other opcodes. AVM values are limited to 4096 bytes, so `ec_pairing_check` is limited by the size of the points in the groups being operated upon. -## ec_multi_exp +## ec_multi_scalar_mul -- Syntax: `ec_multi_exp G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_multi_scalar_mul G` ∋ G: [EC](#field-group-ec) - Bytecode: 0xe3 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn -- **Cost**: BN254g1=80 + 3 per 32 bytes of B; BN254g2=180 + 9 per 32 bytes of B; BLS12_381g1=140 + 4 per 32 bytes of B; BLS12_381g2=350 + 18 per 32 bytes of B +- **Cost**: BN254g1=8000 + 300 per 32 bytes of B; BN254g2=18000 + 900 per 32 bytes of B; BLS12_381g1=14000 + 400 per 32 bytes of B; BLS12_381g2=35000 + 1800 per 32 bytes of B - Availability: v10 A is a list of concatenated points, encoded and checked as described in `ec_add`. B is a list of concatenated scalars which, unlike ec_scalar_mul, must all be exactly 32 bytes long. -The name `ec_multi_exp` was chosen to reflect common usage, but a more consistent name would be `ec_multi_scalar_mul`. AVM values are limited to 4096 bytes, so `ec_multi_exp` is limited by the size of the points in the group being operated upon. +The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more consistent name would be `ec_multi_scalar_mul`. AVM values are limited to 4096 bytes, so `ec_multi_scalar_mul` is limited by the size of the points in the group being operated upon. ## ec_subgroup_check From 13b2abd7eced8bbdb64d625a839faad46149c645 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 15 Aug 2023 12:40:37 -0400 Subject: [PATCH 4/8] final? costs --- dev/TEAL.md | 2 +- dev/TEAL_opcodes.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 7578edc..58d951d 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -384,7 +384,7 @@ return stack matches the name of the input value. | `ec_add g` | for curve points A and B, return the curve point A + B | | `ec_scalar_mul g` | for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. | | `ec_pairing_check g` | 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 | -| `ec_multi_exp g` | for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn | +| `ec_multi_scalar_mul g` | for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn | | `ec_subgroup_check g` | 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. | | `ec_map_to g` | maps field element A to group G | | `+` | A plus B. Fail on overflow. | diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 026b368..2db6529 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1659,7 +1659,7 @@ Fields - Bytecode: 0xe0 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and B, return the curve point A + B -- **Cost**: BN254g1=310; BN254g2=430; BLS12_381g1=540; BLS12_381g2=750 +- **Cost**: BN254g1=125; BN254g2=170; BLS12_381g1=205; BLS12_381g2=290 - Availability: v10 ### EC @@ -1691,7 +1691,7 @@ Does _not_ check if A and B are in the main prime-order subgroup. - Bytecode: 0xe1 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. -- **Cost**: BN254g1=2200; BN254g2=4460; BLS12_381g1=3640; BLS12_381g2=8530 +- **Cost**: BN254g1=1810; BN254g2=3430; BLS12_381g1=2950; BLS12_381g2=6530 - Availability: v10 A is a curve point encoded and checked as described in `ec_add`. Scalar B is interpreted as a big-endian unsigned integer. Fails if B exceeds 32 bytes. @@ -1702,7 +1702,7 @@ A is a curve point encoded and checked as described in `ec_add`. Scalar B is int - Bytecode: 0xe2 {uint8} - Stack: ..., A: []byte, B: []byte → ..., uint64 - 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 -- **Cost**: BN254g1=1 + 18000 per 64 bytes of B; BN254g2=1 + 18000 per 128 bytes of B; BLS12_381g1=45000 + 40000 per 96 bytes of B; BLS12_381g2=45000 + 40000 per 192 bytes of B +- **Cost**: BN254g1=8000 + 7400 per 64 bytes of B; BN254g2=8000 + 7400 per 128 bytes of B; BLS12_381g1=13000 + 10000 per 96 bytes of B; BLS12_381g2=13000 + 10000 per 192 bytes of B - Availability: v10 A and B are concatenated points, encoded and checked as described in `ec_add`. A contains points of the group G, B contains points of the associated group (G2 if G is G1, and vice versa). Fails if A and B have a different number of points, or if any point is not in its described group or outside the main prime-order subgroup - a stronger condition than other opcodes. AVM values are limited to 4096 bytes, so `ec_pairing_check` is limited by the size of the points in the groups being operated upon. @@ -1713,7 +1713,7 @@ A and B are concatenated points, encoded and checked as described in `ec_add`. A - Bytecode: 0xe3 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn -- **Cost**: BN254g1=8000 + 300 per 32 bytes of B; BN254g2=18000 + 900 per 32 bytes of B; BLS12_381g1=14000 + 400 per 32 bytes of B; BLS12_381g2=35000 + 1800 per 32 bytes of B +- **Cost**: BN254g1=3600 + 90 per 32 bytes of B; BN254g2=7200 + 270 per 32 bytes of B; BLS12_381g1=6500 + 95 per 32 bytes of B; BLS12_381g2=14850 + 485 per 32 bytes of B - Availability: v10 A is a list of concatenated points, encoded and checked as described in `ec_add`. B is a list of concatenated scalars which, unlike ec_scalar_mul, must all be exactly 32 bytes long. From 6ce28147041ab00ff9120d5ac9fac5afb2f353e3 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 15 Aug 2023 13:03:50 -0400 Subject: [PATCH 5/8] map to and subgroup check costs --- dev/TEAL_opcodes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 2db6529..6d62531 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -1725,7 +1725,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co - Bytecode: 0xe4 {uint8} - Stack: ..., A: []byte → ..., uint64 - 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. -- **Cost**: BN254g1=50; BN254g2=11500; BLS12_381g1=5600; BLS12_381g2=7100 +- **Cost**: BN254g1=20; BN254g2=3100; BLS12_381g1=1850; BLS12_381g2=2340 - Availability: v10 ## ec_map_to @@ -1734,7 +1734,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co - Bytecode: 0xe5 {uint8} - Stack: ..., A: []byte → ..., []byte - maps field element A to group G -- **Cost**: BN254g1=1700; BN254g2=11000; BLS12_381g1=5600; BLS12_381g2=43000 +- **Cost**: BN254g1=630; BN254g2=3300; BLS12_381g1=1950; BLS12_381g2=8150 - Availability: v10 BN254 points are mapped by the SVDW map. BLS12-381 points are mapped by the SSWU map. From 9303004ec20efd282f8c92b86e9204c15861b978 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 22 Aug 2023 09:45:02 -0400 Subject: [PATCH 6/8] Add a couple global constants --- dev/TEAL.md | 2 ++ dev/TEAL_opcodes.md | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 58d951d..733c0e4 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -632,6 +632,8 @@ Global fields are fields that are common to all the transactions in the group. I | 12 | OpcodeBudget | uint64 | v6 | The remaining cost that can be spent by opcodes in this program. | | 13 | CallerApplicationID | uint64 | v6 | The application ID of the application that called this application. 0 if this application is at the top-level. Application mode only. | | 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | +| 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. | +| 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. | **Asset Fields** diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 6d62531..1dbcca4 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -473,6 +473,8 @@ Fields | 12 | OpcodeBudget | uint64 | v6 | The remaining cost that can be spent by opcodes in this program. | | 13 | CallerApplicationID | uint64 | v6 | The application ID of the application that called this application. 0 if this application is at the top-level. Application mode only. | | 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | +| 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. | +| 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. | ## gtxn @@ -1700,7 +1702,7 @@ A is a curve point encoded and checked as described in `ec_add`. Scalar B is int - Syntax: `ec_pairing_check G` ∋ G: [EC](#field-group-ec) - Bytecode: 0xe2 {uint8} -- Stack: ..., A: []byte, B: []byte → ..., uint64 +- Stack: ..., A: []byte, B: []byte → ..., bool - 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 - **Cost**: BN254g1=8000 + 7400 per 64 bytes of B; BN254g2=8000 + 7400 per 128 bytes of B; BLS12_381g1=13000 + 10000 per 96 bytes of B; BLS12_381g2=13000 + 10000 per 192 bytes of B - Availability: v10 @@ -1723,7 +1725,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co - Syntax: `ec_subgroup_check G` ∋ G: [EC](#field-group-ec) - Bytecode: 0xe4 {uint8} -- Stack: ..., A: []byte → ..., uint64 +- Stack: ..., A: []byte → ..., bool - 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. - **Cost**: BN254g1=20; BN254g2=3100; BLS12_381g1=1850; BLS12_381g2=2340 - Availability: v10 From 155fede10845ca5e82427beef489f82c3a05c760 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Fri, 8 Dec 2023 14:39:09 -0500 Subject: [PATCH 7/8] Change to the version specific presentation --- dev/TEAL.md | 92 ++++++++++++++++++++++++++------------------- dev/TEAL_opcodes.md | 61 ++++++++++++++++++------------ 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/dev/TEAL.md b/dev/TEAL.md index 733c0e4..e25ac4d 100644 --- a/dev/TEAL.md +++ b/dev/TEAL.md @@ -60,17 +60,19 @@ assembly time to do type checking and to provide more informative error messages | Name | Bound | AVM Type | | ---- | ---- | -------- | -| uint64 | x <= 18446744073709551615 | uint64 | -| stateKey | len(x) <= 64 | []byte | -| none | | none | -| method | len(x) == 4 | []byte | -| boxName | 1 <= len(x) <= 64 | []byte | -| bool | x <= 1 | uint64 | -| bigint | len(x) <= 64 | []byte | -| any | | any | -| address | len(x) == 32 | []byte | -| []byte | len(x) <= 4096 | []byte | | [32]byte | len(x) == 32 | []byte | +| [64]byte | len(x) == 64 | []byte | +| [80]byte | len(x) == 80 | []byte | +| []byte | len(x) <= 4096 | []byte | +| address | len(x) == 32 | []byte | +| any | | any | +| bigint | len(x) <= 64 | []byte | +| bool | x <= 1 | uint64 | +| boxName | 1 <= len(x) <= 64 | []byte | +| method | len(x) == 4 | []byte | +| none | | none | +| stateKey | len(x) <= 64 | []byte | +| uint64 | x <= 18446744073709551615 | uint64 | @@ -347,7 +349,7 @@ An application transaction must indicate the action to be taken following the ex Most operations work with only one type of argument, uint64 or bytes, and fail if the wrong type value is on the stack. -Many instructions accept values to designate Accounts, Assets, or Applications. Beginning with v4, these values may be given as an _offset_ in the corresponding Txn fields (Txn.Accounts, Txn.ForeignAssets, Txn.ForeignApps) _or_ as the value itself (a byte-array address for Accounts, or a uint64 ID). The values, however, must still be present in the Txn fields. Before v4, most opcodes required the use of an offset, except for reading account local values of assets or applications, which accepted the IDs directly and did not require the ID to be present in they corresponding _Foreign_ array. (Note that beginning with v4, those IDs _are_ required to be present in their corresponding _Foreign_ array.) See individual opcodes for details. In the case of account offsets or application offsets, 0 is specially defined to Txn.Sender or the ID of the current application, respectively. +Many instructions accept values to designate Accounts, Assets, or Applications. Beginning with v4, these values may be given as an _offset_ in the corresponding Txn fields (Txn.Accounts, Txn.ForeignAssets, Txn.ForeignApps) _or_ as the value itself (a byte-array address for Accounts, or a uint64 ID). The values, however, must still be present in the Txn fields. Before v4, most opcodes required the use of an offset, except for reading account local values of assets or applications, which accepted the IDs directly and did not require the ID to be present in the corresponding _Foreign_ array. (Note that beginning with v4, those IDs _are_ required to be present in their corresponding _Foreign_ array.) See individual opcodes for details. In the case of account offsets or application offsets, 0 is specially defined to Txn.Sender or the ID of the current application, respectively. This summary is supplemented by more detail in the [opcodes document](TEAL_opcodes.md). @@ -367,26 +369,10 @@ an opcode manipulates the stack in such a way that a value changes position but is otherwise unchanged, the name of the output on the return stack matches the name of the input value. -### Arithmetic, Logic, and Cryptographic Operations +### Arithmetic and Logic Operations | Opcode | Description | | - | -- | -| `sha256` | SHA256 hash of value A, yields [32]byte | -| `keccak256` | Keccak256 hash of value A, yields [32]byte | -| `sha512_256` | SHA512_256 hash of value A, yields [32]byte | -| `sha3_256` | SHA3_256 hash of value A, yields [32]byte | -| `ed25519verify` | for (data A, signature B, pubkey C) verify the signature of ("ProgData" \|\| program_hash \|\| data) against the pubkey => {0 or 1} | -| `ed25519verify_bare` | for (data A, signature B, pubkey C) verify the signature of the data against the pubkey => {0 or 1} | -| `ecdsa_verify v` | for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} | -| `ecdsa_pk_recover v` | for (data A, recovery id B, signature C, D) recover a public key | -| `ecdsa_pk_decompress v` | decompress pubkey A into components X, Y | -| `vrf_verify s` | Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. | -| `ec_add g` | for curve points A and B, return the curve point A + B | -| `ec_scalar_mul g` | for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. | -| `ec_pairing_check g` | 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 | -| `ec_multi_scalar_mul g` | for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn | -| `ec_subgroup_check g` | 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. | -| `ec_map_to g` | maps field element A to group G | | `+` | A plus B. Fail on overflow. | | `-` | A minus B. Fail if B > A. | | `/` | A divided by B (truncated division). Fail if B == 0. | @@ -405,7 +391,6 @@ return stack matches the name of the input value. | `==` | A is equal to B => {0 or 1} | | `!=` | A is not equal to B => {0 or 1} | | `!` | A == 0 yields 1; else 0 | -| `len` | yields length of byte value A | | `itob` | converts uint64 A to big-endian byte array, always of length 8 | | `btoi` | converts big-endian byte array A to uint64. Fails if len(A) > 8. Padded by leading 0s if len(A) < 8. | | `%` | A modulo B. Fail if B == 0. | @@ -418,16 +403,17 @@ return stack matches the name of the input value. | `divw` | A,B / C. Fail if C == 0 or if result overflows. | | `divmodw` | W,X = (A,B / C,D); Y,Z = (A,B modulo C,D) | | `expw` | A raised to the Bth power as a 128-bit result in two uint64s. X is the high 64 bits, Y is the low. Fail if A == B == 0 or if the results exceeds 2^128-1 | -| `getbit` | Bth bit of (byte-array or integer) A. If B is greater than or equal to the bit length of the value (8*byte length), the program fails | -| `setbit` | Copy of (byte-array or integer) A, with the Bth bit set to (0 or 1) C. If B is greater than or equal to the bit length of the value (8*byte length), the program fails | -| `getbyte` | Bth byte of A, as an integer. If B is greater than or equal to the array length, the program fails | -| `setbyte` | Copy of A with the Bth byte set to small integer (between 0..255) C. If B is greater than or equal to the array length, the program fails | -| `concat` | join A and B | ### Byte Array Manipulation | Opcode | Description | | - | -- | +| `getbit` | Bth bit of (byte-array or integer) A. If B is greater than or equal to the bit length of the value (8*byte length), the program fails | +| `setbit` | Copy of (byte-array or integer) A, with the Bth bit set to (0 or 1) C. If B is greater than or equal to the bit length of the value (8*byte length), the program fails | +| `getbyte` | Bth byte of A, as an integer. If B is greater than or equal to the array length, the program fails | +| `setbyte` | Copy of A with the Bth byte set to small integer (between 0..255) C. If B is greater than or equal to the array length, the program fails | +| `concat` | join A and B | +| `len` | yields length of byte value A | | `substring s e` | A range of bytes from A starting at S up to but not including E. If E < S, or either is larger than the array length, the program fails | | `substring3` | A range of bytes from A starting at B up to but not including C. If C < B, or either is larger than the array length, the program fails | | `extract s l` | A range of bytes from A starting at S up to but not including S+L. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails | @@ -480,6 +466,27 @@ these results may contain leading zero bytes. | `b^` | A bitwise-xor B. A and B are zero-left extended to the greater of their lengths | | `b~` | A with all bits inverted | +### Cryptographic Operations + +| Opcode | Description | +| - | -- | +| `sha256` | SHA256 hash of value A, yields [32]byte | +| `keccak256` | Keccak256 hash of value A, yields [32]byte | +| `sha512_256` | SHA512_256 hash of value A, yields [32]byte | +| `sha3_256` | SHA3_256 hash of value A, yields [32]byte | +| `ed25519verify` | for (data A, signature B, pubkey C) verify the signature of ("ProgData" \|\| program_hash \|\| data) against the pubkey => {0 or 1} | +| `ed25519verify_bare` | for (data A, signature B, pubkey C) verify the signature of the data against the pubkey => {0 or 1} | +| `ecdsa_verify v` | for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} | +| `ecdsa_pk_recover v` | for (data A, recovery id B, signature C, D) recover a public key | +| `ecdsa_pk_decompress v` | decompress pubkey A into components X, Y | +| `vrf_verify s` | Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. | +| `ec_add g` | for curve points A and B, return the curve point A + B | +| `ec_scalar_mul g` | for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. | +| `ec_pairing_check g` | 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 | +| `ec_multi_scalar_mul g` | for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn | +| `ec_subgroup_check g` | 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. | +| `ec_map_to g` | maps field element A to group G | + ### Loading Values Opcodes for getting data onto the stack. @@ -634,6 +641,7 @@ Global fields are fields that are common to all the transactions in the group. I | 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | | 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. | | 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. | +| 17 | GenesisHash | [32]byte | v10 | The Genesis Hash for the network. | **Asset Fields** @@ -752,6 +760,12 @@ Account fields used in the `acct_params_get` opcode. ### Box Access +Box opcodes that create, delete, or resize boxes affect the minimum +balance requirement of the calling application's account. The change +is immediate, and can be observed after exection by using +`min_balance`. If the account does not possess the new minimum +balance, the opcode fails. + All box related opcodes fail immediately if used in a ClearStateProgram. This behavior is meant to discourage Smart Contract authors from depending upon the availability of boxes in a ClearState @@ -764,19 +778,21 @@ are sure to be _available_. | Opcode | Description | | - | -- | -| `box_create` | create a box named A, of length B. Fail if A is empty or B exceeds 32,768. Returns 0 if A already existed, else 1 | +| `box_create` | create a box named A, of length B. Fail if the name A is empty or B exceeds 32,768. Returns 0 if A already existed, else 1 | | `box_extract` | read C bytes from box A, starting at offset B. Fail if A does not exist, or the byte range is outside A's size. | | `box_replace` | write byte-array C into box A, starting at offset B. Fail if A does not exist, or the byte range is outside A's size. | +| `box_splice` | set box A to contain its previous bytes up to index B, followed by D, followed by the original bytes of A that began at index B+C. | | `box_del` | delete box named A if it exists. Return 1 if A existed, 0 otherwise | | `box_len` | X is the length of box A if A exists, else 0. Y is 1 if A exists, else 0. | | `box_get` | X is the contents of box A if A exists, else ''. Y is 1 if A exists, else 0. | | `box_put` | replaces the contents of box A with byte-array B. Fails if A exists and len(B) != len(box A). Creates A if it does not exist | +| `box_resize` | change the size of box named A to be of length B, adding zero bytes to end or removing bytes from the end, as needed. Fail if the name A is empty, A is not an existing box, or B exceeds 32,768. | ### Inner Transactions The following opcodes allow for "inner transactions". Inner transactions allow stateful applications to have many of the effects -of a true top-level transaction, programatically. However, they are +of a true top-level transaction, programmatically. However, they are different in significant ways. The most important differences are that they are not signed, duplicates are not rejected, and they do not appear in the block in the usual away. Instead, their effects are @@ -787,7 +803,7 @@ account that has been rekeyed to that hash. In v5, inner transactions may perform `pay`, `axfer`, `acfg`, and `afrz` effects. After executing an inner transaction with -`itxn_submit`, the effects of the transaction are visible begining +`itxn_submit`, the effects of the transaction are visible beginning with the next instruction with, for example, `balance` and `min_balance` checks. In v6, inner transactions may also perform `keyreg` and `appl` effects. Inner `appl` calls fail if they attempt @@ -807,7 +823,7 @@ setting is used when `itxn_submit` executes. For this purpose `Type` and `TypeEnum` are considered to be the same field. When using `itxn_field` to set an array field (`ApplicationArgs` `Accounts`, `Assets`, or `Applications`) each use adds an element to the end of -the the array, rather than setting the entire array at once. +the array, rather than setting the entire array at once. `itxn_field` fails immediately for unsupported fields, unsupported transaction types, or improperly typed values for a particular diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 1dbcca4..26b3b45 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -6,7 +6,7 @@ abstract: > Algorand allows transactions to be effectively signed by a small program. If the program evaluates to true then the transaction is allowed. This document defines the language opcodes and byte encoding. --- -# Opcodes +# v10 Opcodes Ops have a 'cost' of 1 unless otherwise specified. @@ -22,32 +22,26 @@ Ops have a 'cost' of 1 unless otherwise specified. - Bytecode: 0x01 - Stack: ..., A: []byte → ..., [32]byte - SHA256 hash of value A, yields [32]byte -- **Cost**: - - 7 (v1) - - 35 (since v2) +- **Cost**: 35 ## keccak256 - Bytecode: 0x02 - Stack: ..., A: []byte → ..., [32]byte - Keccak256 hash of value A, yields [32]byte -- **Cost**: - - 26 (v1) - - 130 (since v2) +- **Cost**: 130 ## sha512_256 - Bytecode: 0x03 - Stack: ..., A: []byte → ..., [32]byte - SHA512_256 hash of value A, yields [32]byte -- **Cost**: - - 9 (v1) - - 45 (since v2) +- **Cost**: 45 ## ed25519verify - Bytecode: 0x04 -- Stack: ..., A: []byte, B: []byte, C: []byte → ..., bool +- Stack: ..., A: []byte, B: [64]byte, C: [32]byte → ..., bool - for (data A, signature B, pubkey C) verify the signature of ("ProgData" || program_hash || data) against the pubkey => {0 or 1} - **Cost**: 1900 @@ -57,9 +51,9 @@ The 32 byte public key is the last element on the stack, preceded by the 64 byte - Syntax: `ecdsa_verify V` ∋ V: [ECDSA](#field-group-ecdsa) - Bytecode: 0x05 {uint8} -- Stack: ..., A: []byte, B: []byte, C: []byte, D: []byte, E: []byte → ..., bool +- Stack: ..., A: [32]byte, B: []byte, C: []byte, D: []byte, E: []byte → ..., bool - for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} -- **Cost**: Secp256k1=1700; Secp256r1=2500 +- **Cost**: Secp256k1=1700; Secp256r1=2500 - Availability: v5 ### ECDSA @@ -80,7 +74,7 @@ The 32 byte Y-component of a public key is the last element on the stack, preced - Bytecode: 0x06 {uint8} - Stack: ..., A: []byte → ..., X: []byte, Y: []byte - decompress pubkey A into components X, Y -- **Cost**: Secp256k1=650; Secp256r1=2400 +- **Cost**: Secp256k1=650; Secp256r1=2400 - Availability: v5 The 33 byte public key in a compressed form to be decompressed into X and Y (top) components. All values are big-endian encoded. @@ -89,7 +83,7 @@ The 33 byte public key in a compressed form to be decompressed into X and Y (top - Syntax: `ecdsa_pk_recover V` ∋ V: [ECDSA](#field-group-ecdsa) - Bytecode: 0x07 {uint8} -- Stack: ..., A: []byte, B: uint64, C: []byte, D: []byte → ..., X: []byte, Y: []byte +- Stack: ..., A: [32]byte, B: uint64, C: [32]byte, D: [32]byte → ..., X: []byte, Y: []byte - for (data A, recovery id B, signature C, D) recover a public key - **Cost**: 2000 - Availability: v5 @@ -475,6 +469,7 @@ Fields | 14 | CallerApplicationAddress | address | v6 | The application address of the application that called this application. ZeroAddress if this application is at the top-level. Application mode only. | | 15 | AssetCreateMinBalance | uint64 | v10 | The additional minimum balance required to create (and opt-in to) an asset. | | 16 | AssetOptInMinBalance | uint64 | v10 | The additional minimum balance required to opt-in to an asset. | +| 17 | GenesisHash | [32]byte | v10 | The Genesis Hash for the network. | ## gtxn @@ -1150,7 +1145,7 @@ pushints args are not added to the intcblock during assembly processes ## ed25519verify_bare - Bytecode: 0x84 -- Stack: ..., A: []byte, B: []byte, C: []byte → ..., bool +- Stack: ..., A: []byte, B: [64]byte, C: [32]byte → ..., bool - for (data A, signature B, pubkey C) verify the signature of the data against the pubkey => {0 or 1} - **Cost**: 1900 - Availability: v7 @@ -1501,7 +1496,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with - Bytecode: 0xb9 - Stack: ..., A: boxName, B: uint64 → ..., bool -- create a box named A, of length B. Fail if A is empty or B exceeds 32,768. Returns 0 if A already existed, else 1 +- create a box named A, of length B. Fail if the name A is empty or B exceeds 32,768. Returns 0 if A already existed, else 1 - Availability: v8 - Mode: Application @@ -1621,7 +1616,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo - Syntax: `vrf_verify S` ∋ S: [vrf_verify](#field-group-vrf_verify) - Bytecode: 0xd0 {uint8} -- Stack: ..., A: []byte, B: []byte, C: []byte → ..., X: []byte, Y: bool +- Stack: ..., A: []byte, B: [80]byte, C: [32]byte → ..., X: []byte, Y: bool - Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. - **Cost**: 5700 - Availability: v7 @@ -1655,13 +1650,31 @@ Fields | 1 | BlkTimestamp | uint64 | | +## box_splice + +- Bytecode: 0xd2 +- Stack: ..., A: boxName, B: uint64, C: uint64, D: []byte → ... +- set box A to contain its previous bytes up to index B, followed by D, followed by the original bytes of A that began at index B+C. +- Availability: v10 +- Mode: Application + +Boxes are of constant length. If C < len(D), then len(D)-C bytes will be removed from the end. If C > len(D), zero bytes will be appended to the end to reach the box length. + +## box_resize + +- Bytecode: 0xd3 +- Stack: ..., A: boxName, B: uint64 → ... +- change the size of box named A to be of length B, adding zero bytes to end or removing bytes from the end, as needed. Fail if the name A is empty, A is not an existing box, or B exceeds 32,768. +- Availability: v10 +- Mode: Application + ## ec_add - Syntax: `ec_add G` ∋ G: [EC](#field-group-ec) - Bytecode: 0xe0 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and B, return the curve point A + B -- **Cost**: BN254g1=125; BN254g2=170; BLS12_381g1=205; BLS12_381g2=290 +- **Cost**: BN254g1=125; BN254g2=170; BLS12_381g1=205; BLS12_381g2=290 - Availability: v10 ### EC @@ -1693,7 +1706,7 @@ Does _not_ check if A and B are in the main prime-order subgroup. - Bytecode: 0xe1 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. -- **Cost**: BN254g1=1810; BN254g2=3430; BLS12_381g1=2950; BLS12_381g2=6530 +- **Cost**: BN254g1=1810; BN254g2=3430; BLS12_381g1=2950; BLS12_381g2=6530 - Availability: v10 A is a curve point encoded and checked as described in `ec_add`. Scalar B is interpreted as a big-endian unsigned integer. Fails if B exceeds 32 bytes. @@ -1704,7 +1717,7 @@ A is a curve point encoded and checked as described in `ec_add`. Scalar B is int - Bytecode: 0xe2 {uint8} - Stack: ..., A: []byte, B: []byte → ..., bool - 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 -- **Cost**: BN254g1=8000 + 7400 per 64 bytes of B; BN254g2=8000 + 7400 per 128 bytes of B; BLS12_381g1=13000 + 10000 per 96 bytes of B; BLS12_381g2=13000 + 10000 per 192 bytes of B +- **Cost**: BN254g1=8000 + 7400 per 64 bytes of B; BN254g2=8000 + 7400 per 128 bytes of B; BLS12_381g1=13000 + 10000 per 96 bytes of B; BLS12_381g2=13000 + 10000 per 192 bytes of B - Availability: v10 A and B are concatenated points, encoded and checked as described in `ec_add`. A contains points of the group G, B contains points of the associated group (G2 if G is G1, and vice versa). Fails if A and B have a different number of points, or if any point is not in its described group or outside the main prime-order subgroup - a stronger condition than other opcodes. AVM values are limited to 4096 bytes, so `ec_pairing_check` is limited by the size of the points in the groups being operated upon. @@ -1715,7 +1728,7 @@ A and B are concatenated points, encoded and checked as described in `ec_add`. A - Bytecode: 0xe3 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn -- **Cost**: BN254g1=3600 + 90 per 32 bytes of B; BN254g2=7200 + 270 per 32 bytes of B; BLS12_381g1=6500 + 95 per 32 bytes of B; BLS12_381g2=14850 + 485 per 32 bytes of B +- **Cost**: BN254g1=3600 + 90 per 32 bytes of B; BN254g2=7200 + 270 per 32 bytes of B; BLS12_381g1=6500 + 95 per 32 bytes of B; BLS12_381g2=14850 + 485 per 32 bytes of B - Availability: v10 A is a list of concatenated points, encoded and checked as described in `ec_add`. B is a list of concatenated scalars which, unlike ec_scalar_mul, must all be exactly 32 bytes long. @@ -1727,7 +1740,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co - Bytecode: 0xe4 {uint8} - Stack: ..., A: []byte → ..., bool - 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. -- **Cost**: BN254g1=20; BN254g2=3100; BLS12_381g1=1850; BLS12_381g2=2340 +- **Cost**: BN254g1=20; BN254g2=3100; BLS12_381g1=1850; BLS12_381g2=2340 - Availability: v10 ## ec_map_to @@ -1736,7 +1749,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co - Bytecode: 0xe5 {uint8} - Stack: ..., A: []byte → ..., []byte - maps field element A to group G -- **Cost**: BN254g1=630; BN254g2=3300; BLS12_381g1=1950; BLS12_381g2=8150 +- **Cost**: BN254g1=630; BN254g2=3300; BLS12_381g1=1950; BLS12_381g2=8150 - Availability: v10 BN254 points are mapped by the SVDW map. BLS12-381 points are mapped by the SSWU map. From afdeabe9cf2544692fa8fff1413301cc008b99c6 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Mon, 11 Dec 2023 16:08:24 -0500 Subject: [PATCH 8/8] change unicode that was causing trouble --- dev/TEAL_opcodes.md | 132 ++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/dev/TEAL_opcodes.md b/dev/TEAL_opcodes.md index 26b3b45..bbb6e50 100644 --- a/dev/TEAL_opcodes.md +++ b/dev/TEAL_opcodes.md @@ -49,7 +49,7 @@ The 32 byte public key is the last element on the stack, preceded by the 64 byte ## ecdsa_verify -- Syntax: `ecdsa_verify V` ∋ V: [ECDSA](#field-group-ecdsa) +- Syntax: `ecdsa_verify V` where V: [ECDSA](#field-group-ecdsa) - Bytecode: 0x05 {uint8} - Stack: ..., A: [32]byte, B: []byte, C: []byte, D: []byte, E: []byte → ..., bool - for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} @@ -70,7 +70,7 @@ The 32 byte Y-component of a public key is the last element on the stack, preced ## ecdsa_pk_decompress -- Syntax: `ecdsa_pk_decompress V` ∋ V: [ECDSA](#field-group-ecdsa) +- Syntax: `ecdsa_pk_decompress V` where V: [ECDSA](#field-group-ecdsa) - Bytecode: 0x06 {uint8} - Stack: ..., A: []byte → ..., X: []byte, Y: []byte - decompress pubkey A into components X, Y @@ -81,7 +81,7 @@ The 33 byte public key in a compressed form to be decompressed into X and Y (top ## ecdsa_pk_recover -- Syntax: `ecdsa_pk_recover V` ∋ V: [ECDSA](#field-group-ecdsa) +- Syntax: `ecdsa_pk_recover V` where V: [ECDSA](#field-group-ecdsa) - Bytecode: 0x07 {uint8} - Stack: ..., A: [32]byte, B: uint64, C: [32]byte, D: [32]byte → ..., X: []byte, Y: []byte - for (data A, recovery id B, signature C, D) recover a public key @@ -249,7 +249,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## intcblock -- Syntax: `intcblock UINT ...` ∋ UINT ...: a block of int constant values +- Syntax: `intcblock UINT ...` where UINT ...: a block of int constant values - Bytecode: 0x20 {varuint count, [varuint ...]} - Stack: ... → ... - prepare block of uint64 constants for use by intc @@ -258,7 +258,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## intc -- Syntax: `intc I` ∋ I: an index in the intcblock +- Syntax: `intc I` where I: an index in the intcblock - Bytecode: 0x21 {uint8} - Stack: ... → ..., uint64 - Ith constant from intcblock @@ -289,7 +289,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## bytecblock -- Syntax: `bytecblock BYTES ...` ∋ BYTES ...: a block of byte constant values +- Syntax: `bytecblock BYTES ...` where BYTES ...: a block of byte constant values - Bytecode: 0x26 {varuint count, [varuint length, bytes ...]} - Stack: ... → ... - prepare block of byte-array constants for use by bytec @@ -298,7 +298,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## bytec -- Syntax: `bytec I` ∋ I: an index in the bytecblock +- Syntax: `bytec I` where I: an index in the bytecblock - Bytecode: 0x27 {uint8} - Stack: ... → ..., []byte - Ith constant from bytecblock @@ -329,7 +329,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## arg -- Syntax: `arg N` ∋ N: an arg index +- Syntax: `arg N` where N: an arg index - Bytecode: 0x2c {uint8} - Stack: ... → ..., []byte - Nth LogicSig argument @@ -365,7 +365,7 @@ The notation J,K indicates that two uint64 values J and K are interpreted as a u ## txn -- Syntax: `txn F` ∋ F: [txn](#field-group-txn) +- Syntax: `txn F` where F: [txn](#field-group-txn) - Bytecode: 0x31 {uint8} - Stack: ... → ..., any - field F of current transaction @@ -441,7 +441,7 @@ Fields (see [transaction reference](https://developer.algorand.org/docs/referenc ## global -- Syntax: `global F` ∋ F: [global](#field-group-global) +- Syntax: `global F` where F: [global](#field-group-global) - Bytecode: 0x32 {uint8} - Stack: ... → ..., any - global field F @@ -474,7 +474,7 @@ Fields ## gtxn -- Syntax: `gtxn T F` ∋ T: transaction group index, F: [txn](#field-group-txn) +- Syntax: `gtxn T F` where T: transaction group index, F: [txn](#field-group-txn) - Bytecode: 0x33 {uint8}, {uint8} - Stack: ... → ..., any - field F of the Tth transaction in the current group @@ -483,21 +483,21 @@ for notes on transaction fields available, see `txn`. If this transaction is _i_ ## load -- Syntax: `load I` ∋ I: position in scratch space to load from +- Syntax: `load I` where I: position in scratch space to load from - Bytecode: 0x34 {uint8} - Stack: ... → ..., any - Ith scratch space value. All scratch spaces are 0 at program start. ## store -- Syntax: `store I` ∋ I: position in scratch space to store to +- Syntax: `store I` where I: position in scratch space to store to - Bytecode: 0x35 {uint8} - Stack: ..., A → ... - store A to the Ith scratch space ## txna -- Syntax: `txna F I` ∋ F: [txna](#field-group-txna), I: transaction field array index +- Syntax: `txna F I` where F: [txna](#field-group-txna), I: transaction field array index - Bytecode: 0x36 {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F of the current transaction
`txna` can be called using `txn` with 2 immediates. @@ -520,7 +520,7 @@ Fields (see [transaction reference](https://developer.algorand.org/docs/referenc ## gtxna -- Syntax: `gtxna T F I` ∋ T: transaction group index, F: [txna](#field-group-txna), I: transaction field array index +- Syntax: `gtxna T F I` where T: transaction group index, F: [txna](#field-group-txna), I: transaction field array index - Bytecode: 0x37 {uint8}, {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F from the Tth transaction in the current group
`gtxna` can be called using `gtxn` with 3 immediates. @@ -528,7 +528,7 @@ Fields (see [transaction reference](https://developer.algorand.org/docs/referenc ## gtxns -- Syntax: `gtxns F` ∋ F: [txn](#field-group-txn) +- Syntax: `gtxns F` where F: [txn](#field-group-txn) - Bytecode: 0x38 {uint8} - Stack: ..., A: uint64 → ..., any - field F of the Ath transaction in the current group @@ -538,7 +538,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## gtxnsa -- Syntax: `gtxnsa F I` ∋ F: [txna](#field-group-txna), I: transaction field array index +- Syntax: `gtxnsa F I` where F: [txna](#field-group-txna), I: transaction field array index - Bytecode: 0x39 {uint8}, {uint8} - Stack: ..., A: uint64 → ..., any - Ith value of the array field F from the Ath transaction in the current group
`gtxnsa` can be called using `gtxns` with 2 immediates. @@ -546,7 +546,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## gload -- Syntax: `gload T I` ∋ T: transaction group index, I: position in scratch space to load from +- Syntax: `gload T I` where T: transaction group index, I: position in scratch space to load from - Bytecode: 0x3a {uint8}, {uint8} - Stack: ... → ..., any - Ith scratch space value of the Tth transaction in the current group @@ -557,7 +557,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## gloads -- Syntax: `gloads I` ∋ I: position in scratch space to load from +- Syntax: `gloads I` where I: position in scratch space to load from - Bytecode: 0x3b {uint8} - Stack: ..., A: uint64 → ..., any - Ith scratch space value of the Ath transaction in the current group @@ -568,7 +568,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## gaid -- Syntax: `gaid T` ∋ T: transaction group index +- Syntax: `gaid T` where T: transaction group index - Bytecode: 0x3c {uint8} - Stack: ... → ..., uint64 - ID of the asset or application created in the Tth transaction of the current group @@ -603,7 +603,7 @@ for notes on transaction fields available, see `txn`. If top of stack is _i_, `g ## bnz -- Syntax: `bnz TARGET` ∋ TARGET: branch offset +- Syntax: `bnz TARGET` where TARGET: branch offset - Bytecode: 0x40 {int16 (big-endian)} - Stack: ..., A: uint64 → ... - branch to TARGET if value A is not zero @@ -614,7 +614,7 @@ At v2 it became allowed to branch to the end of the program exactly after the la ## bz -- Syntax: `bz TARGET` ∋ TARGET: branch offset +- Syntax: `bz TARGET` where TARGET: branch offset - Bytecode: 0x41 {int16 (big-endian)} - Stack: ..., A: uint64 → ... - branch to TARGET if value A is zero @@ -624,7 +624,7 @@ See `bnz` for details on how branches work. `bz` inverts the behavior of `bnz`. ## b -- Syntax: `b TARGET` ∋ TARGET: branch offset +- Syntax: `b TARGET` where TARGET: branch offset - Bytecode: 0x42 {int16 (big-endian)} - Stack: ... → ... - branch unconditionally to TARGET @@ -648,7 +648,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## bury -- Syntax: `bury N` ∋ N: depth +- Syntax: `bury N` where N: depth - Bytecode: 0x45 {uint8} - Stack: ..., A → ... - replace the Nth value from the top of the stack with A. bury 0 fails. @@ -656,7 +656,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## popn -- Syntax: `popn N` ∋ N: stack depth +- Syntax: `popn N` where N: stack depth - Bytecode: 0x46 {uint8} - Stack: ..., [N items] → ... - remove N values from the top of the stack @@ -664,7 +664,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## dupn -- Syntax: `dupn N` ∋ N: copy count +- Syntax: `dupn N` where N: copy count - Bytecode: 0x47 {uint8} - Stack: ..., A → ..., A, [N copies of A] - duplicate A, N times @@ -691,7 +691,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## dig -- Syntax: `dig N` ∋ N: depth +- Syntax: `dig N` where N: depth - Bytecode: 0x4b {uint8} - Stack: ..., A, [N items] → ..., A, [N items], A - Nth value from the top of the stack. dig 0 is equivalent to dup @@ -713,7 +713,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## cover -- Syntax: `cover N` ∋ N: depth +- Syntax: `cover N` where N: depth - Bytecode: 0x4e {uint8} - Stack: ..., [N items], A → ..., A, [N items] - remove top of stack, and place it deeper in the stack such that N elements are above it. Fails if stack depth <= N. @@ -721,7 +721,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## uncover -- Syntax: `uncover N` ∋ N: depth +- Syntax: `uncover N` where N: depth - Bytecode: 0x4f {uint8} - Stack: ..., A, [N items] → ..., [N items], A - remove the value at depth N in the stack and shift above items down so the Nth deep value is on top of the stack. Fails if stack depth <= N. @@ -738,7 +738,7 @@ See `bnz` for details on how branches work. `b` always jumps to the offset. ## substring -- Syntax: `substring S E` ∋ S: start position, E: end position +- Syntax: `substring S E` where S: start position, E: end position - Bytecode: 0x51 {uint8}, {uint8} - Stack: ..., A: []byte → ..., []byte - A range of bytes from A starting at S up to but not including E. If E < S, or either is larger than the array length, the program fails @@ -785,7 +785,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on ## extract -- Syntax: `extract S L` ∋ S: start position, L: length +- Syntax: `extract S L` where S: start position, L: length - Bytecode: 0x57 {uint8}, {uint8} - Stack: ..., A: []byte → ..., []byte - A range of bytes from A starting at S up to but not including S+L. If L is 0, then extract to the end of the string. If S or S+L is larger than the array length, the program fails @@ -821,7 +821,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on ## replace2 -- Syntax: `replace2 S` ∋ S: start position +- Syntax: `replace2 S` where S: start position - Bytecode: 0x5c {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - Copy of A with the bytes starting at S replaced by the bytes of B. Fails if S+len(B) exceeds len(A)
`replace2` can be called using `replace` with 1 immediate. @@ -836,7 +836,7 @@ When A is a uint64, index 0 is the least significant bit. Setting bit 3 to 1 on ## base64_decode -- Syntax: `base64_decode E` ∋ E: [base64](#field-group-base64) +- Syntax: `base64_decode E` where E: [base64](#field-group-base64) - Bytecode: 0x5e {uint8} - Stack: ..., A: []byte → ..., []byte - decode A which was base64-encoded using _encoding_ E. Fail if A is not base64 encoded with encoding E @@ -859,7 +859,7 @@ Encodings ## json_ref -- Syntax: `json_ref R` ∋ R: [json_ref](#field-group-json_ref) +- Syntax: `json_ref R` where R: [json_ref](#field-group-json_ref) - Bytecode: 0x5f {uint8} - Stack: ..., A: []byte, B: []byte → ..., any - key B's value, of type R, from a [valid](jsonspec.md) utf-8 encoded json object A @@ -985,7 +985,7 @@ Deleting a key which is already absent has no effect on the application global s ## asset_holding_get -- Syntax: `asset_holding_get F` ∋ F: [asset_holding](#field-group-asset_holding) +- Syntax: `asset_holding_get F` where F: [asset_holding](#field-group-asset_holding) - Bytecode: 0x70 {uint8} - Stack: ..., A, B: uint64 → ..., X: any, Y: bool - X is field F from account A's holding of asset B. Y is 1 if A is opted into B, else 0 @@ -1006,7 +1006,7 @@ params: Txn.Accounts offset (or, since v4, an _available_ address), asset id (or ## asset_params_get -- Syntax: `asset_params_get F` ∋ F: [asset_params](#field-group-asset_params) +- Syntax: `asset_params_get F` where F: [asset_params](#field-group-asset_params) - Bytecode: 0x71 {uint8} - Stack: ..., A: uint64 → ..., X: any, Y: bool - X is field F from asset A. Y is 1 if A exists, else 0 @@ -1037,7 +1037,7 @@ params: Txn.ForeignAssets offset (or, since v4, an _available_ asset id. Return: ## app_params_get -- Syntax: `app_params_get F` ∋ F: [app_params](#field-group-app_params) +- Syntax: `app_params_get F` where F: [app_params](#field-group-app_params) - Bytecode: 0x72 {uint8} - Stack: ..., A: uint64 → ..., X: any, Y: bool - X is field F from app A. Y is 1 if A exists, else 0 @@ -1065,7 +1065,7 @@ params: Txn.ForeignApps offset or an _available_ app id. Return: did_exist flag ## acct_params_get -- Syntax: `acct_params_get F` ∋ F: [acct_params](#field-group-acct_params) +- Syntax: `acct_params_get F` where F: [acct_params](#field-group-acct_params) - Bytecode: 0x73 {uint8} - Stack: ..., A → ..., X: any, Y: bool - X is field F from account A. Y is 1 if A owns positive algos, else 0 @@ -1104,7 +1104,7 @@ params: Txn.Accounts offset (or, since v4, an _available_ account address), _ava ## pushbytes -- Syntax: `pushbytes BYTES` ∋ BYTES: a byte constant +- Syntax: `pushbytes BYTES` where BYTES: a byte constant - Bytecode: 0x80 {varuint length, bytes} - Stack: ... → ..., []byte - immediate BYTES @@ -1114,7 +1114,7 @@ pushbytes args are not added to the bytecblock during assembly processes ## pushint -- Syntax: `pushint UINT` ∋ UINT: an int constant +- Syntax: `pushint UINT` where UINT: an int constant - Bytecode: 0x81 {varuint} - Stack: ... → ..., uint64 - immediate UINT @@ -1124,7 +1124,7 @@ pushint args are not added to the intcblock during assembly processes ## pushbytess -- Syntax: `pushbytess BYTES ...` ∋ BYTES ...: a list of byte constants +- Syntax: `pushbytess BYTES ...` where BYTES ...: a list of byte constants - Bytecode: 0x82 {varuint count, [varuint length, bytes ...]} - Stack: ... → ..., [N items] - push sequences of immediate byte arrays to stack (first byte array being deepest) @@ -1134,7 +1134,7 @@ pushbytess args are not added to the bytecblock during assembly processes ## pushints -- Syntax: `pushints UINT ...` ∋ UINT ...: a list of int constants +- Syntax: `pushints UINT ...` where UINT ...: a list of int constants - Bytecode: 0x83 {varuint count, [varuint ...]} - Stack: ... → ..., [N items] - push sequence of immediate uints to stack in the order they appear (first uint being deepest) @@ -1152,7 +1152,7 @@ pushints args are not added to the intcblock during assembly processes ## callsub -- Syntax: `callsub TARGET` ∋ TARGET: branch offset +- Syntax: `callsub TARGET` where TARGET: branch offset - Bytecode: 0x88 {int16 (big-endian)} - Stack: ... → ... - branch unconditionally to TARGET, saving the next instruction on the call stack @@ -1171,7 +1171,7 @@ If the current frame was prepared by `proto A R`, `retsub` will remove the 'A' a ## proto -- Syntax: `proto A R` ∋ A: number of arguments, R: number of return values +- Syntax: `proto A R` where A: number of arguments, R: number of return values - Bytecode: 0x8a {uint8}, {uint8} - Stack: ... → ... - Prepare top call frame for a retsub that will assume A args and R return values. @@ -1181,7 +1181,7 @@ Fails unless the last instruction executed was a `callsub`. ## frame_dig -- Syntax: `frame_dig I` ∋ I: frame slot +- Syntax: `frame_dig I` where I: frame slot - Bytecode: 0x8b {int8} - Stack: ... → ..., any - Nth (signed) value from the frame pointer. @@ -1189,7 +1189,7 @@ Fails unless the last instruction executed was a `callsub`. ## frame_bury -- Syntax: `frame_bury I` ∋ I: frame slot +- Syntax: `frame_bury I` where I: frame slot - Bytecode: 0x8c {int8} - Stack: ..., A → ... - replace the Nth (signed) value from the frame pointer in the stack with A @@ -1197,7 +1197,7 @@ Fails unless the last instruction executed was a `callsub`. ## switch -- Syntax: `switch TARGET ...` ∋ TARGET ...: list of labels +- Syntax: `switch TARGET ...` where TARGET ...: list of labels - Bytecode: 0x8d {varuint count, [int16 (big-endian) ...]} - Stack: ..., A: uint64 → ... - branch to the Ath label. Continue at following instruction if index A exceeds the number of labels. @@ -1205,7 +1205,7 @@ Fails unless the last instruction executed was a `callsub`. ## match -- Syntax: `match TARGET ...` ∋ TARGET ...: list of labels +- Syntax: `match TARGET ...` where TARGET ...: list of labels - Bytecode: 0x8e {varuint count, [int16 (big-endian) ...]} - Stack: ..., [A1, A2, ..., AN], B → ... - given match cases from A[1] to A[N], branch to the Ith label where A[I] = B. Continue to the following instruction if no matches are found. @@ -1427,7 +1427,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## itxn_field -- Syntax: `itxn_field F` ∋ F: [txn](#field-group-txn) +- Syntax: `itxn_field F` where F: [txn](#field-group-txn) - Bytecode: 0xb2 {uint8} - Stack: ..., A → ... - set field F of the current inner transaction to A @@ -1448,7 +1448,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## itxn -- Syntax: `itxn F` ∋ F: [txn](#field-group-txn) +- Syntax: `itxn F` where F: [txn](#field-group-txn) - Bytecode: 0xb4 {uint8} - Stack: ... → ..., any - field F of the last inner transaction @@ -1457,7 +1457,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## itxna -- Syntax: `itxna F I` ∋ F: [txna](#field-group-txna), I: a transaction field array index +- Syntax: `itxna F I` where F: [txna](#field-group-txna), I: a transaction field array index - Bytecode: 0xb5 {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F of the last inner transaction @@ -1476,7 +1476,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## gitxn -- Syntax: `gitxn T F` ∋ T: transaction group index, F: [txn](#field-group-txn) +- Syntax: `gitxn T F` where T: transaction group index, F: [txn](#field-group-txn) - Bytecode: 0xb7 {uint8}, {uint8} - Stack: ... → ..., any - field F of the Tth transaction in the last inner group submitted @@ -1485,7 +1485,7 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with ## gitxna -- Syntax: `gitxna T F I` ∋ T: transaction group index, F: [txna](#field-group-txna), I: transaction field array index +- Syntax: `gitxna T F I` where T: transaction group index, F: [txna](#field-group-txna), I: transaction field array index - Bytecode: 0xb8 {uint8}, {uint8}, {uint8} - Stack: ... → ..., any - Ith value of the array field F from the Tth transaction in the last inner group submitted @@ -1556,7 +1556,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## txnas -- Syntax: `txnas F` ∋ F: [txna](#field-group-txna) +- Syntax: `txnas F` where F: [txna](#field-group-txna) - Bytecode: 0xc0 {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F of the current transaction @@ -1564,7 +1564,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## gtxnas -- Syntax: `gtxnas T F` ∋ T: transaction group index, F: [txna](#field-group-txna) +- Syntax: `gtxnas T F` where T: transaction group index, F: [txna](#field-group-txna) - Bytecode: 0xc1 {uint8}, {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F from the Tth transaction in the current group @@ -1572,7 +1572,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## gtxnsas -- Syntax: `gtxnsas F` ∋ F: [txna](#field-group-txna) +- Syntax: `gtxnsas F` where F: [txna](#field-group-txna) - Bytecode: 0xc2 {uint8} - Stack: ..., A: uint64, B: uint64 → ..., any - Bth value of the array field F from the Ath transaction in the current group @@ -1596,7 +1596,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## itxnas -- Syntax: `itxnas F` ∋ F: [txna](#field-group-txna) +- Syntax: `itxnas F` where F: [txna](#field-group-txna) - Bytecode: 0xc5 {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F of the last inner transaction @@ -1605,7 +1605,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## gitxnas -- Syntax: `gitxnas T F` ∋ T: transaction group index, F: [txna](#field-group-txna) +- Syntax: `gitxnas T F` where T: transaction group index, F: [txna](#field-group-txna) - Bytecode: 0xc6 {uint8}, {uint8} - Stack: ..., A: uint64 → ..., any - Ath value of the array field F from the Tth transaction in the last inner group submitted @@ -1614,7 +1614,7 @@ For boxes that exceed 4,096 bytes, consider `box_create`, `box_extract`, and `bo ## vrf_verify -- Syntax: `vrf_verify S` ∋ S: [vrf_verify](#field-group-vrf_verify) +- Syntax: `vrf_verify S` where S: [vrf_verify](#field-group-vrf_verify) - Bytecode: 0xd0 {uint8} - Stack: ..., A: []byte, B: [80]byte, C: [32]byte → ..., X: []byte, Y: bool - Verify the proof B of message A against pubkey C. Returns vrf output and verification flag. @@ -1634,7 +1634,7 @@ Standards ## block -- Syntax: `block F` ∋ F: [block](#field-group-block) +- Syntax: `block F` where F: [block](#field-group-block) - Bytecode: 0xd1 {uint8} - Stack: ..., A: uint64 → ..., any - field F of block A. Fail unless A falls between txn.LastValid-1002 and txn.FirstValid (exclusive) @@ -1670,7 +1670,7 @@ Boxes are of constant length. If C < len(D), then len(D)-C bytes will be removed ## ec_add -- Syntax: `ec_add G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_add G` where G: [EC](#field-group-ec) - Bytecode: 0xe0 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and B, return the curve point A + B @@ -1702,7 +1702,7 @@ Does _not_ check if A and B are in the main prime-order subgroup. ## ec_scalar_mul -- Syntax: `ec_scalar_mul G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_scalar_mul G` where G: [EC](#field-group-ec) - Bytecode: 0xe1 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve point A and scalar B, return the curve point BA, the point A multiplied by the scalar B. @@ -1713,7 +1713,7 @@ A is a curve point encoded and checked as described in `ec_add`. Scalar B is int ## ec_pairing_check -- Syntax: `ec_pairing_check G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_pairing_check G` where G: [EC](#field-group-ec) - Bytecode: 0xe2 {uint8} - Stack: ..., A: []byte, B: []byte → ..., bool - 1 if the product of the pairing of each point in A with its respective point in B is equal to the identity element of the target group Gt, else 0 @@ -1724,7 +1724,7 @@ A and B are concatenated points, encoded and checked as described in `ec_add`. A ## ec_multi_scalar_mul -- Syntax: `ec_multi_scalar_mul G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_multi_scalar_mul G` where G: [EC](#field-group-ec) - Bytecode: 0xe3 {uint8} - Stack: ..., A: []byte, B: []byte → ..., []byte - for curve points A and scalars B, return curve point B0A0 + B1A1 + B2A2 + ... + BnAn @@ -1736,7 +1736,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co ## ec_subgroup_check -- Syntax: `ec_subgroup_check G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_subgroup_check G` where G: [EC](#field-group-ec) - Bytecode: 0xe4 {uint8} - Stack: ..., A: []byte → ..., bool - 1 if A is in the main prime-order subgroup of G (including the point at infinity) else 0. Program fails if A is not in G at all. @@ -1745,7 +1745,7 @@ The name `ec_multi_scalar_mul` was chosen to reflect common usage, but a more co ## ec_map_to -- Syntax: `ec_map_to G` ∋ G: [EC](#field-group-ec) +- Syntax: `ec_map_to G` where G: [EC](#field-group-ec) - Bytecode: 0xe5 {uint8} - Stack: ..., A: []byte → ..., []byte - maps field element A to group G