diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 10d86f476a..df429c07ce 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -439,6 +439,13 @@ dup; dup falcon_verify ` +const bmodexpNonsense = ` +pushbytes 0x0123456789abcd +pushbytes 0x0123456789abcd +pushbytes 0x0123456789abcd +bmodexp +` + const v8Nonsense = v7Nonsense + switchNonsense + frameNonsense + matchNonsense + boxNonsense const v9Nonsense = v8Nonsense @@ -450,7 +457,7 @@ const spliceNonsence = ` const v10Nonsense = v9Nonsense + pairingNonsense + spliceNonsence -const v11Nonsense = v10Nonsense + incentiveNonsense + stateProofNonsense +const v11Nonsense = v10Nonsense + incentiveNonsense + stateProofNonsense + bmodexpNonsense const v6Compiled = "2004010002b7a60c26050242420c68656c6c6f20776f726c6421070123456789abcd208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292b0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f2310231123122313231418191a1b1c28171615400003290349483403350222231d4a484848482b50512a632223524100034200004322602261222704634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f447825225314225427042455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f012a57000823810858235b235a2359b03139330039b1b200b322c01a23c1001a2323c21a23c3233e233f8120af06002a494905002a49490700b400b53a03b6b7043cb8033a0c2349c42a9631007300810881088120978101c53a8101c6003a" @@ -475,8 +482,9 @@ const v10Compiled = v9Compiled + pairingCompiled + spliceCompiled const incentiveCompiled = "757401" const stateProofCompiled = "80070123456789abcd86494985" +const bmodexpCompiled = "80070123456789abcd80070123456789abcd80070123456789abcde6" -const V11Compiled = v10Compiled + incentiveCompiled + stateProofCompiled +const V11Compiled = v10Compiled + incentiveCompiled + stateProofCompiled + bmodexpCompiled var nonsense = map[uint64]string{ 1: v1Nonsense, @@ -557,7 +565,7 @@ func TestAssemble(t *testing.T) { } } -var experiments = []uint64{spOpcodesVersion} +var experiments = []uint64{spOpcodesVersion, bmodexpVersion} // TestExperimental forces a conscious choice to promote "experimental" opcode // groups. This will fail when we increment vFuture's LogicSigVersion. If we had diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 3bab156561..e0467ebe16 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -257,21 +257,22 @@ var opDescByName = map[string]OpDesc{ "proto": {"Prepare top call frame for a retsub that will assume A args and R return values.", "Fails unless the last instruction executed was a `callsub`.", []string{"number of arguments", "number of return values"}}, "retsub": {"pop the top instruction from the call stack and branch to it", "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.", nil}, - "b+": {"A plus B. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b-": {"A minus B. A and B are interpreted as big-endian unsigned integers. Fail on underflow.", "", nil}, - "b/": {"A divided by B (truncated division). A and B are interpreted as big-endian unsigned integers. Fail if B is zero.", "", nil}, - "b*": {"A times B. A and B are interpreted as big-endian unsigned integers.", "", nil}, - "b<": {"1 if A is less than B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b>": {"1 if A is greater than B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b<=": {"1 if A is less than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b>=": {"1 if A is greater than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b==": {"1 if A is equal to B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b!=": {"0 if A is equal to B, else 1. A and B are interpreted as big-endian unsigned integers", "", nil}, - "b%": {"A modulo B. A and B are interpreted as big-endian unsigned integers. Fail if B is zero.", "", nil}, - "b|": {"A bitwise-or B. A and B are zero-left extended to the greater of their lengths", "", nil}, - "b&": {"A bitwise-and B. A and B are zero-left extended to the greater of their lengths", "", nil}, - "b^": {"A bitwise-xor B. A and B are zero-left extended to the greater of their lengths", "", nil}, - "b~": {"A with all bits inverted", "", nil}, + "b+": {"A plus B. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b-": {"A minus B. A and B are interpreted as big-endian unsigned integers. Fail on underflow.", "", nil}, + "b/": {"A divided by B (truncated division). A and B are interpreted as big-endian unsigned integers. Fail if B is zero.", "", nil}, + "b*": {"A times B. A and B are interpreted as big-endian unsigned integers.", "", nil}, + "b<": {"1 if A is less than B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b>": {"1 if A is greater than B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b<=": {"1 if A is less than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b>=": {"1 if A is greater than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b==": {"1 if A is equal to B, else 0. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b!=": {"0 if A is equal to B, else 1. A and B are interpreted as big-endian unsigned integers", "", nil}, + "b%": {"A modulo B. A and B are interpreted as big-endian unsigned integers. Fail if B is zero.", "", nil}, + "bmodexp": {"A raised to the Bth power modulo C. A, B and C are interpreted as big-endian unsigned integers limited to 4096 bytes. Fail if C is zero.", "", nil}, + "b|": {"A bitwise-or B. A and B are zero-left extended to the greater of their lengths", "", nil}, + "b&": {"A bitwise-and B. A and B are zero-left extended to the greater of their lengths", "", nil}, + "b^": {"A bitwise-xor B. A and B are zero-left extended to the greater of their lengths", "", nil}, + "b~": {"A with all bits inverted", "", nil}, "bsqrt": {"The largest integer I such that I^2 <= A. A and I are interpreted as big-endian unsigned integers", "", nil}, @@ -352,7 +353,7 @@ func OpDocExtra(opName string) string { var OpGroups = map[string][]string{ "Arithmetic": {"+", "-", "/", "*", "<", ">", "<=", ">=", "&&", "||", "shl", "shr", "sqrt", "bitlen", "exp", "==", "!=", "!", "itob", "btoi", "%", "|", "&", "^", "~", "mulw", "addw", "divw", "divmodw", "expw"}, "Byte Array Manipulation": {"getbit", "setbit", "getbyte", "setbyte", "concat", "len", "substring", "substring3", "extract", "extract3", "extract_uint16", "extract_uint32", "extract_uint64", "replace2", "replace3", "base64_decode", "json_ref"}, - "Byte Array Arithmetic": {"b+", "b-", "b/", "b*", "b<", "b>", "b<=", "b>=", "b==", "b!=", "b%", "bsqrt"}, + "Byte Array Arithmetic": {"b+", "b-", "b/", "b*", "b<", "b>", "b<=", "b>=", "b==", "b!=", "b%", "bsqrt", "bmodexp"}, "Byte Array Logic": {"b|", "b&", "b^", "b~"}, "Cryptography": {"sha256", "keccak256", "sha512_256", "sha3_256", "sumhash512", "falcon_verify", "ed25519verify", "ed25519verify_bare", "ecdsa_verify", "ecdsa_pk_recover", "ecdsa_pk_decompress", "vrf_verify", "ec_add", "ec_scalar_mul", "ec_pairing_check", "ec_multi_scalar_mul", "ec_subgroup_check", "ec_map_to"}, "Loading Values": {"intcblock", "intc", "intc_0", "intc_1", "intc_2", "intc_3", "pushint", "pushints", "bytecblock", "bytec", "bytec_0", "bytec_1", "bytec_2", "bytec_3", "pushbytes", "pushbytess", "bzero", "arg", "arg_0", "arg_1", "arg_2", "arg_3", "args", "txn", "gtxn", "txna", "txnas", "gtxna", "gtxnas", "gtxns", "gtxnsa", "gtxnsas", "global", "load", "loads", "store", "stores", "gload", "gloads", "gloadss", "gaid", "gaids"}, diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 4da436a1b6..639085e5ed 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -2325,6 +2325,33 @@ func opBytesNeq(cx *EvalContext) error { return opNot(cx) } +func opBytesModExp(cx *EvalContext) error { + result := new(big.Int) + last := len(cx.Stack) - 1 // z + prev := last - 1 // y + pprev := last - 2 // x + + if len(cx.Stack[last].Bytes) > maxStringSize || len(cx.Stack[prev].Bytes) > maxStringSize || len(cx.Stack[pprev].Bytes) > maxStringSize { + return errors.New("bmodexp attempted on large byte-array") + } + + z := new(big.Int).SetBytes(cx.Stack[last].Bytes) + y := new(big.Int).SetBytes(cx.Stack[prev].Bytes) + x := new(big.Int).SetBytes(cx.Stack[pprev].Bytes) + if z.BitLen() == 0 { + return errors.New("modulo by zero") + } + + result.Exp(x, y, z) + if result.Sign() < 0 { + return errors.New("bmodexp would have negative result") + } + + cx.Stack[pprev].Bytes = result.Bytes() + cx.Stack = cx.Stack[:prev] + return nil +} + func opBytesModulo(cx *EvalContext) error { result := new(big.Int) var inner error diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index abff0ddb83..41ffa3cdeb 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -3254,6 +3254,7 @@ func TestReturnTypes(t *testing.T) { "box_create": "int 9; +; box_create", // make the size match the 10 in CreateBox "box_put": "byte 0x010203040506; concat; box_put", // make the 4 byte arg into a 10 + "bmodexp": ": byte 0x0102030405; byte 0x010203040506; byte 0x01020304050607; bmodexp", } /* Make sure the specialCmd tests the opcode in question */ diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index c8f7a8bc5f..3bdd0eb473 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -5065,6 +5065,55 @@ func TestBitLen(t *testing.T) { } +func TestBytesModExp(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + type TestOutcome int + const ( + Accept TestOutcome = iota + Reject + Panic + ) + type ModexpTestVector struct { + Base string + Exponent string + Modulus string + Result string + TestOutcome TestOutcome + } + modexpTestVectors := []ModexpTestVector{ + {"0x01", "0x01", "0x", "0x00", Panic}, // Modulo of 0 should panic + {"0x01", "0x01", "0x0000", "0x00", Panic}, // Modulo of 0 should panic + {"0x00", "0x00", "0x01", "0x", Accept}, + {"0xfecd94e51b7227573693217cffee2069b16e86509aaeb141e3918b9522b48dfdb8cf6f842a5b25602d3a509addb561ddbee848b4a0d68473f142e0b895c99a7e5c1dd2a9d3aac4e65e87b61a7cb4689afeaf1a28fa642bd35a56e6fc123b60c1fd34c33fce472dc5a6bbcaa136a89af1df0b4c85aa99cf34f11b0d605709778f876295eee07828000ff37fa045b279fa12e0b0e99e525705acca77b54d4210fdcde48374152e97753fb9aae79d48e82abfb9e9afc102e78fe3d3b21218982ca78d044291b8d8ae715ead3b7690de00f67a91ec0eb85d4c0c2736215f14678a8ea239f8425151f7e31bb39000a6", "0xd27369499b4e38c037632ee1f1a963f1f4d9275f8a514a335ed46f64061dd354e7438f233a77ba2d1d372158c17078409e72699e909452a663497145d7f4d65932e8a49a9add52783531e5352d17085028ed0a7551439e4e4bf7c287ba0b9176532f300c2710d86d3380f64fced370fd61c8f3b52c4136aff1b8f7190ea220ee50d25182b37990e09f765c2aa65e4bb8930fc7d1e3d8466d988610a5ad1b7067851b95d7c88d5a57a2e710860193580c015fe067627dcbe157887c29b9709ed8e04dee40521fbf6f7472ef0e38cef45ea6b1b0dc3f9d8a0ca11376ac9f92512596d82ce1000e4ad0551f807060afc2", "0x27a889b93153f4a045dc7583c169fe4a86fa1909ccc1a4183fe577be60905c76e3b2990b525ab40afc36dd9009b6e5b89c7789f09f72ee36bf011501b797a7520f0f35b636f5f1457908e12746a13243b27e02814570d46ceb35bdb8bf5dbd45b1854f859ef5d1c6fc7c21450ead9002fb99e05879d7531463fb565bbe9fc0c336d11e686f2d7cd9f96423243bad8907a955966df2", "0x1159c95dfd2d6010f7df10078b3bca2681d8bc892596462d1bed9beb64b2d349c6b2422d12cd5c759c517e9d6861b3cd41a301b671c09c06fc8c463f958a82695f451b5b348361e8016105453d79b63cd6df2d0ab9dc37228dc71effeb7036b7daa971f94507b53d673df31ccad70295f26a91b648c962db1c278f97f7c6848c9b6eb14a66c350d86a541aafae7f22b1d64876369e", Accept}, + {"0xb83ede301f43216b751761b94103ca4c01352ddc0eec69abf69ecf70fdd9f7aacf9dda9518eba3862d138bd2e7336b0a8621e83b22e25b5347507336b061e38d48c083722b523c33509c1b9a0d30a3da8ca7f5b2fb8d0095ca48a7d4c5c9a34f222b43eaa3c66cd18c37b0ea4016356ebfb3a888db8a3c90d03ebab84d1b43a57d34cf781a78df7ae3f87102a12bb6412a42a642d649f1a349235b080322e585745c6ebaffd49919f1bed598414e8ea6edb191e17868e4d2353337509fd29c7053f67e27b261e478f37b5d59e4f667f4d51bb354ffd9a90e94bd8ec947564033ee1d578b1fe8d7", "0x183e792802e3e670be1d570a5658672500c287625582b7743de11e8e80361613a86419e464fdf57e0c504c155e6b7febdf1a5833f39b7fa5891386f8dfaa985dad5b1bf0001ada176bf05b5129c3d16fcad6be460feaed369cbc986929f94be839a82b5341c7a791f014f5ed0fdf0f3c6a1becbe23c4e0aa4ca9495a087a37464ff46745b6e7139c0e1fc5d2ec53d48495714bb1ccbadc0dca5275fc33424f0c9c057cd41b4d094c87fba00015ec5ed12ee115c3704898c4e702bd64de7879eeccee135957125dcf1c43b5a4ce424b", "0x379f241e6a9c0aed86705cf6ecbc9bfb6533cd757ed53facc7ec1f95c9139068560a3e185ae01401e0e05251eb2b036986cb17be92d8f46622800a64ae8d0b8d2d2b649a4d6be28e2a6fb705f349bd7513a055a33c92e140ad9643e7710459be1f1b4930f46a447bc0ec0552602d76f3616b2030613976afa00b961e7fa909ce2bf77a040a7ba72277c5406883ef2946e7571e192c3c0bfe5e9f66a786a9", "0x0fe90441ccf81a0a8227155936d90dada4", Reject}, + {"0x43f4df0787ae52b4433b7a5fe0a55993cb1cf79b0e9318f85a90b7ba7c0ced2603d464113b82ea7986ac5249e2266db648ebb23529c0a1d732ffdacdcba22fc88e184d", "0x0402678ddba1793fa049e81f30b2a825d97db413573f13d9ec9dd54523e5ee202308b9c0c20b26d4949c626ad62d3768e38316b1c7fc0a1ca3f84697f350408d10318bf39d8dffad2254cd5519de8a0defb8e17aad2a5f05cb5ac0f25c0f5274653406216212ad38c733959adbfb31ca531dddc9f8e5ce0478fe30b12d422732b401c103e96140cba3ec026511f0b3d2355d079910834f0cec1847bb9d9a2d040f095b2761e4bd26e79600ae7c575b80c54893131eb26302c4107e7f83acc5754840d8588e4803fe3bcdbd3c7a26a109a22407de5809cdbd525f8fd41fac561e301f08928638", "0xdd9224855029854c02a3c1b92a62a41e8d32ef64dbfd39858413df75631ce8b442d845fe256f6bc6b842f192fa27ba627a45bbcee0b9a606f761d3d753566cf8ed2a6cc3edffb011d190a2b7f31c15923e58da6b7aaaa775fa948cac4723c164bb3c084354bcd90b1dc19d338a4074a68d4ee1e81eca0fa2b1eeaee0254aa307a3adeabe06550996b59a4d3572021e3a5cb670d113030b155eed5be224d0800296d0b4181066dbdb36ceabb178b29527b2ecd5fc8443801e2e13422a4c9004013be315c6fbfe48e3d1ac858886426381aef76d8e0fd3a2ca9b1147f2da2cfef3988cec0d227666fe8b5919a67ed8", "0x0e2611da26bfb2a255a28659b32c4ad4031c9a519f0008280c315ebe0981428c717f70e293956abf2313286742bfa569e70ba883e337c33d0ba54f1eed68499f9be4e174451c22d940e4e50dd0c26578b1da11a3f174ba77f85988839c80c916de370274e30864de05ddb805713d2cad6d7c908db8ceec7e7e280eb65dd9e6f74bd031b1d6db72475697af7c8851a22b003c23b6139818576e11c8dbe667792e54cba5acce53b18747a09d43696042d3024bf04d23c3b2264527bd26d4163402389687dcbdacb1b75dfb1ed156b2faf5bb4f3284298b558ed4dd5ba754df0b7a5c3bdbf8f4619487ace3992e5921", Accept}, + {"0x43e3f4a2a30309f52331c8b23e9f2c2c5bfb5c3bef8b69a4b58ddd185b8b63b1f23b21ee7a0e85893433facfc135c7e21f39e06a4ad71bc26268acb480907a883685963bbc4c4ec52ab52c6ae681cd61245c3d8bd8f5bba2b5e4e123357dba12235c61ce1549f5c60f400afa453f5db65bf72b1d5d20b254b0c306a86a9e68ac2f0e226e", "0x4504b93f905be9f35e38e507d0fd5f666ecd212fde7579f23a47cc9910b54f9b420c2fcd54e8fbec2bb24ccd050fdc0300d3", "0x381ddee4f5f83bc09da93ede2d13022628f443f4aef73ef740ea50e6aaf377f67c3c21c1d858c46978076a5926e9d803999f911f2af2bcaa82ae02f0b3c48f4467ed545763d18c9b157376cc7a6aac2b0669abbc6894b5784f01bb786545933ad8bfd975a041ff03cc81b60677b7afc0aa059c4c47a41af3f30e33fe08743686cbc15049e26e13cfbf719515229281c59ee99b7a9a6aaa110df9a2d16b58394f704d4982ceed8e441a62d809c0a842f16bc85e8a9bb6ff3bf027cc0e73cca9ff285bc74e08d857629f9b5c0d051dcf88221ac9687245e7ee7e6d877072fde59222ff", "0x9312bfc6064fcbe01c7bf1ac1bba80a2b0607faaac2f0f102270129abf5a56dc50b3145c79aa5babda0dc85d7205f742da145d65764147fe9ca027d0e15affc9963ec7abaac1a025654213d91a22a11055f00621dd3c1aa5b7180e70de3a68ac7d3dde0088adf0006fe80950ee8d3c3e8bad87d68f6d9e45af1729ea2ffcd81b117f48be33e1fa1254a1e49bf67cf6def9df3d7030f88ae0d0cda5c999bcdb2c2f631508abc5a6ce3080c27a274d5b7d7d", Reject}, + {"0x2e6bebf6e587185ce2b74db841a5f7d681aedd53b7d0fa76a1e9dbeb3dcd60f021affa201c192257d89642dbf6afffd1a272c0f7b4e30b88", "0x4396069f7dd294400e725602c6c8ad4f3fe0301578c62537138c3bf98211c096a86a1448b2e57b0a005dec2eb631d8eb2aa9974ba3c3343a5170cac4094296937606fd318439f7f40dcb2c6b5a4f6059829e87b39eae61a40cc27ae22466f2c7b5cf78d7a2299aed6df7c5e69c80f450f979bfae39a5ed82343a02cc61e877079ee26b42b9afc01d1f60627b4bfbfe12a5", "0x676326af0980eeee7f6deeb6b77609df8bc847aa6e20c1f15bb070d8650c9427a4862b1e08fbed2f88ff18e1085c152ef80534b9dfd56a7c488c7068103e76ae730715997214d3c528515d572296941cf89250010b3bef7fbf175e55faeaf36f5746814ef94da60bdedfc8b8fd02434cd5122f56c5c36567a6a627e7cda8a36e90756e29cf8091465d140e5037bce8abc4f59b9160f580affb0845095071764754449fb485dd5ba1af", "0x2356ca087f69fe3fd129686b9406f448eb71bf04576cfb19e01731f541fb487409a7ac705b32de77511dc7952aa26980661cfc77d08a69e74eedeea60befe46af667b8c95b946c7535b3ac0c6210944a1f3804a7cf16c033adad01e6cddf29eee99db6245f3408db3dc77d32d83666535c60bbdcf79a251c5690fbb93830ec942607182fe0dd45739b9587fad72c98a8462f1fde205253b08b857d91a947192310df13a592f1417b78", Accept}, + {"0xefe0ed52aa48ac1954d289cddc48fe2fa9d2fd0a30ec80558d120df81dfd1bd5bdafc6db6c1be75408c8913667966a67eeae3d4660c51365cd126acbcff0896a242f998d6cdd12effe1519826eb869762835d33e30ecfa9fa1c3c26b8481d106e301cb9d7d53d5499fe7b38107e222de26cb2a5dd2cdba60dca3f8cfc35e512b5f4ba6429be53041a8fbcea34546b3562f20668d414d8025448b46fdcf2b6665ac6eab707642b5", "0x815178f225ffa7735b81058aeb7618db87d8e027b56d76dba76acfca305df3bf1039e86a2485d525894528", "0xe8cb702599322c16a07935ebaa175e1da2c090807209942f43df5c6db4732f08235da740218ce9ab2b654e53d8f102a0a4b0aca861270ca6788aebcd223d2ac3640ccdaa43aac14970751a6eafed7180a51a4d6de93b3e5e7e74f8a55bef5caf5a096e11354cae423d770fe1bc6682752b639e7510d7a2b77d44bf104c3333ce029d4f7e49255fd50e6ee2ba1002fc7c2c17b9f17053dc11135bc5b5e5f6e7cc075b3d0e658affc64b24819a3a8458a4467faa76112ffb6c061a96a199f2ef4f4e9a2b91687c7be85f009029c60495", "0x5437f7393e93182cc931add5c2ab61373c0a83a9c9713b91c0d880325cb6153a369feb6c2755c68f18444e1e67f0b16bcfba717c3b61833ae1c4a28b64b6860aaaf9fdebede0ee2e6aa88b18ac1e39ab5307678669de5d1046e800585adca7c560f923eb3511afccb3eb52c507a9e96a266aac75439b289a0756415f50658d07ff5ef236f3ffc6e5a57f4b5e27785737fbb77f4e0c780de0dbdafe2de14ec61344346ecd6f2db6cf6f0b12c95d7103f68fb837d022504a04f69a", Reject}, + {"0x5aaf78fa0137ed7a80a760cb1f00fe76f8dba1048bf35db85ed43d7081fff9c7fd61e71fe7a42ef861c081786d0b92053263a92d0491403f31bcddac325b7012d1078c19c17a16a22b57eed143f6d1aa3c7cb823479f8314a87db3142aaf50a8ec1eb8afec5c09bc5c1f97b5f617681ff9cafaf6b5bd6f186892e2016f58", "0xda431fbf1062b9ef1be8812d7d6870257f11aba4b9f27ce4f3db13200111a2e6862219042331d8e31c2438f9f6bc0dd77708200480d5c26632b9bac060daf4a4f74fd966fab0fcaea1853b3478eb6c3088b732a5ac20c0c13d5a3ae65fe23b", "0x57fb8a5ff255e23da812337e4145d4eaa11529de3894741886ae99a839bed9a10ae06719a0a820a34295a62e2534eaf0431b6be1b5187384dff144e828932622af0624976cb4b9660833385346cbc2d55379d0c72eda68a10202be3e8c92cc8d151864d2d465abc9ec6759f4f2e341cd4dcf4a4fac1ce4a480e065eaf859dff8799646bf9638535979cc8b616215b9c737d59bc0146520d415511aaef942a923afa58435d9d5", "0x05a08475905993424f0ce051bba9213855c74d601ed82089ec8f804b5e29275ec2b6b53ea813c1931a248418500a1a73e6c94a7a9f72df4cfd863218a928c999e8bb65106c606bc40e068b732e312b63b6ce5f6370402f9f576fe33d981ed9f06bcbc653aea90e3a2e7359560001e787119f8ee1d90695753582e52e077bd848c8c6eec421a2b79531fc15798c044ead4a81bc40b98964c9b21ff49c0a5da2d20752ca63a0d8", Accept}, + {"0x7afd6101ca03eee6db2ee5bd17c4df4645d3099c5b69d01efddd9656f14a5085534f1bbab0e9213e827715c5bd4abf8f9a7a1052cf1afb2b6332ec74c4b18e6a6ef976bfb70c2d", "0x33fe913d149938164862fe788a7dfaa901690376e3e193523fc92afc6e8e1ef4fb40ed01273231942a2b5b4d7d59b5e65b3397fa61c7453b1559b177b1b160fff8cf48867097e887c4be19a6c33ba156cae132090b4f8b7e54a501431a04f066b003ca2868e4cef065a1d1f5903ee581ac3c97003d71160fe3e643a42126c08e17c6b1675c8407bc6f3ad4ccb858535cbe132c8b48e9fbedcf2e222cec319a95a3c4f75df10463b11bd97e810c623c92ab8efe5d31f0d89ad85ac8", "0x757c4d7f4d108027363a6181eb0d950bc515afe7d7dd103cfadce2295030430840a45b4e541c4966e9f991ee219b26ace999b7a0d07d9e10414644daf591b09a04696705cc2555ec7c05dfc9e51d349ae25a96106f99a620d4962edae0b940c62276c6", "0x65fbf3319e294a7109a1f607c3379360f78df96c940b7a244c725a23cc632f4dd4c6283bddbe8dfb46c69de79dc337aea892708c5de1a27c6a422f41fce6ab5b19100de32081c2a066e51cacfbf5d8c76bed6a502ada2ff044619e3f5d196d401ba3a45cc8ebc8767750239ecf326b3eb658ef970baeefa40fd1e1dbcbdd7d6a7838d6a20595765021d5e3f8fe6a96c4a346f8a26990317de9c57a6a309a132a6b6dfad21c1d7f707e8607e497b7cca31b9d5bf804af4d46", Reject}, + } + + for _, modexpTestVector := range modexpTestVectors { + progText := fmt.Sprintf(`byte %s +byte %s +byte %s +bmodexp + +byte %s +==`, modexpTestVector.Base, modexpTestVector.Exponent, modexpTestVector.Modulus, modexpTestVector.Result) + if modexpTestVector.TestOutcome == Accept { + testAccepts(t, progText, 11) + } else if modexpTestVector.TestOutcome == Reject { + testRejects(t, progText, 11) + } else if modexpTestVector.TestOutcome == Panic { + testPanics(t, progText, 11) + } + } + +} + func TestBytesMath(t *testing.T) { partitiontest.PartitionTest(t) diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index f3f8bfe37d..f1af4f87ae 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -81,6 +81,7 @@ const spliceVersion = 10 // box splicing/resizing const incentiveVersion = 11 // block fields, heartbeat const spOpcodesVersion = 11 // falcon_verify, sumhash512 +const bmodexpVersion = 11 // bmodexp // Unlimited Global Storage opcodes const boxVersion = 8 // box_* @@ -798,6 +799,7 @@ var OpSpecs = []OpSpec{ costByField("g", &EcGroups, []int{ BN254g1: 630, BN254g2: 3_300, BLS12_381g1: 1_950, BLS12_381g2: 8_150})}, + {0xe6, "bmodexp", opBytesModExp, proto("bbb:b"), bmodexpVersion, costly(2000)}, // TODO: refine cost model for bmodexp } // OpcodesByVersion returns list of opcodes available in a specific version of TEAL diff --git a/data/transactions/logic/teal.tmLanguage.json b/data/transactions/logic/teal.tmLanguage.json index 53984e8dd2..118a250a76 100644 --- a/data/transactions/logic/teal.tmLanguage.json +++ b/data/transactions/logic/teal.tmLanguage.json @@ -76,7 +76,7 @@ }, { "name": "keyword.operator.teal", - "match": "^(\\!|\\!\\=|%|\u0026|\u0026\u0026|\\*|\\+|\\-|/|\\\u003c|\\\u003c\\=|\\=\\=|\\\u003e|\\\u003e\\=|\\^|addw|bitlen|btoi|divmodw|divw|exp|expw|itob|mulw|shl|shr|sqrt|\\||\\|\\||\\~|b\\!\\=|b%|b\\*|b\\+|b\\-|b/|b\\\u003c|b\\\u003c\\=|b\\=\\=|b\\\u003e|b\\\u003e\\=|bsqrt|b\u0026|b\\^|b\\||b\\~|base64_decode|concat|extract|extract3|extract_uint16|extract_uint32|extract_uint64|getbit|getbyte|json_ref|len|replace2|replace3|setbit|setbyte|substring|substring3|ec_add|ec_map_to|ec_multi_scalar_mul|ec_pairing_check|ec_scalar_mul|ec_subgroup_check|ecdsa_pk_decompress|ecdsa_pk_recover|ecdsa_verify|ed25519verify|ed25519verify_bare|falcon_verify|keccak256|sha256|sha3_256|sha512_256|sumhash512|vrf_verify|gitxn|gitxna|gitxnas|itxn|itxn_begin|itxn_field|itxn_next|itxn_submit|itxna|itxnas)\\b" + "match": "^(\\!|\\!\\=|%|\u0026|\u0026\u0026|\\*|\\+|\\-|/|\\\u003c|\\\u003c\\=|\\=\\=|\\\u003e|\\\u003e\\=|\\^|addw|bitlen|btoi|divmodw|divw|exp|expw|itob|mulw|shl|shr|sqrt|\\||\\|\\||\\~|b\\!\\=|b%|bmodexp|b\\*|b\\+|b\\-|b/|b\\\u003c|b\\\u003c\\=|b\\=\\=|b\\\u003e|b\\\u003e\\=|bsqrt|b\u0026|b\\^|b\\||b\\~|base64_decode|concat|extract|extract3|extract_uint16|extract_uint32|extract_uint64|getbit|getbyte|json_ref|len|replace2|replace3|setbit|setbyte|substring|substring3|ec_add|ec_map_to|ec_multi_scalar_mul|ec_pairing_check|ec_scalar_mul|ec_subgroup_check|ecdsa_pk_decompress|ecdsa_pk_recover|ecdsa_verify|ed25519verify|ed25519verify_bare|falcon_verify|keccak256|sha256|sha3_256|sha512_256|sumhash512|vrf_verify|gitxn|gitxna|gitxnas|itxn|itxn_begin|itxn_field|itxn_next|itxn_submit|itxna|itxnas)\\b" } ] },