From aa862604d7087f33492541e7491a1e50155ef469 Mon Sep 17 00:00:00 2001 From: giulio Date: Thu, 18 Apr 2024 09:29:40 +0200 Subject: [PATCH 1/5] Add new teal opcodes mimc_BN254 and mimc_BLS12_381 --- data/transactions/logic/assembler_test.go | 43 +++++++++----- data/transactions/logic/crypto.go | 61 ++++++++++++++++++++ data/transactions/logic/crypto_test.go | 2 +- data/transactions/logic/doc.go | 9 ++- data/transactions/logic/evalStateful_test.go | 4 ++ data/transactions/logic/opcodes.go | 3 + data/transactions/logic/teal.tmLanguage.json | 2 +- 7 files changed, 105 insertions(+), 19 deletions(-) diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 3f609fd7ee..4b2966a529 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -434,6 +434,15 @@ dup; dup falcon_verify ` +const mimcBN254Nonsense = ` +pushbytes 0x11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff +mimc_BN254 +` +const mimcBLS12381Nonsense = ` +pushbytes 0x11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff +mimc_BLS12_381 +` + const v8Nonsense = v7Nonsense + switchNonsense + frameNonsense + matchNonsense + boxNonsense const v9Nonsense = v8Nonsense @@ -445,7 +454,7 @@ const spliceNonsence = ` const v10Nonsense = v9Nonsense + pairingNonsense + spliceNonsence -const v11Nonsense = v10Nonsense + stateProofNonsense +const v11Nonsense = v10Nonsense + stateProofNonsense + mimcBN254Nonsense + mimcBLS12381Nonsense const v6Compiled = "2004010002b7a60c26050242420c68656c6c6f20776f726c6421070123456789abcd208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292b0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f2310231123122313231418191a1b1c28171615400003290349483403350222231d4a484848482b50512a632223524100034200004322602261222704634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f447825225314225427042455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f012a57000823810858235b235a2359b03139330039b1b200b322c01a23c1001a2323c21a23c3233e233f8120af06002a494905002a49490700b400b53a03b6b7043cb8033a0c2349c42a9631007300810881088120978101c53a8101c6003a" @@ -468,8 +477,10 @@ const spliceCompiled = "d2d3" const v10Compiled = v9Compiled + pairingCompiled + spliceCompiled const stateProofCompiled = "80070123456789abcd86494985" +const mimcBN254Compiled = "802011223344556677889900aabbccddeeff11223344556677889900aabbccddeefff0" +const mimcBLS12381Compiled = "802011223344556677889900aabbccddeeff11223344556677889900aabbccddeefff1" -const V11Compiled = v10Compiled + stateProofCompiled +const V11Compiled = v10Compiled + stateProofCompiled + mimcBN254Compiled + mimcBLS12381Compiled var nonsense = map[uint64]string{ 1: v1Nonsense, @@ -3168,7 +3179,7 @@ func TestMacros(t *testing.T) { #define ==? ==; bnz pushint 1; pushint 2; ==? label1 err - label1: + label1: pushint 1`, ) @@ -3206,19 +3217,19 @@ func TestMacros(t *testing.T) { pushbytes 0xddf2554d txna ApplicationArgs 0 == - bnz kickstart - pushbytes 0x903f4535 + bnz kickstart + pushbytes 0x903f4535 txna ApplicationArgs 0 == - bnz portal_transfer + bnz portal_transfer kickstart: pushint 1 portal_transfer: pushint 1 `, ` - #define abi-route txna ApplicationArgs 0; ==; bnz - method "kickstart(account)void"; abi-route kickstart - method "portal_transfer(byte[])byte[]"; abi-route portal_transfer + #define abi-route txna ApplicationArgs 0; ==; bnz + method "kickstart(account)void"; abi-route kickstart + method "portal_transfer(byte[])byte[]"; abi-route portal_transfer kickstart: pushint 1 portal_transfer: @@ -3274,7 +3285,7 @@ add: extract_uint32 stores - load 1; load 2; + + load 1; load 2; + store 255 int 255 @@ -3298,11 +3309,11 @@ add: #define abi-decode-uint32 ;int 0; extract_uint32; #define abi-encode-uint32 ;itob;extract 4 0; -#define abi-encode-bytes ;dup; len; abi-encode-uint16; swap; concat; +#define abi-encode-bytes ;dup; len; abi-encode-uint16; swap; concat; #define abi-decode-bytes ;extract 2 0; -// abi method handling -#define abi-route ;txna ApplicationArgs 0; ==; bnz +// abi method handling +#define abi-route ;txna ApplicationArgs 0; ==; bnz #define abi-return ;pushbytes 0x151f7c75; swap; concat; log; int 1; return; // stanza: "set $var from-{type}" @@ -3331,15 +3342,15 @@ echo: // add handler -method "add(uint32,uint32)uint32"; abi-route add +method "add(uint32,uint32)uint32"; abi-route add add: #define x 1 - parse x from-uint32 + parse x from-uint32 #define y 2 parse y from-uint32 - #define sum 255 + #define sum 255 load x; load y; +; store sum returns sum as-uint32 diff --git a/data/transactions/logic/crypto.go b/data/transactions/logic/crypto.go index c5c39b654c..cd67ecdcc5 100644 --- a/data/transactions/logic/crypto.go +++ b/data/transactions/logic/crypto.go @@ -30,8 +30,69 @@ import ( "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-sumhash" "golang.org/x/crypto/sha3" + + bls12_381fr "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + bls12_381mimc "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/mimc" + bn254fr "github.com/consensys/gnark-crypto/ecc/bn254/fr" + bn254mimc "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" ) +// mimc on curve BLS12-381 is implemented for compatibility with zk circuits, +// matching the implementation in circuits generated by gnark +func opMimcBLS12381(cx *EvalContext) error { + last := len(cx.Stack) - 1 + data := cx.Stack[last].Bytes + if len(data)%32 != 0 { + return fmt.Errorf("the input data must be a multiple of 32 bytes") + } + hasher := bls12_381mimc.NewMiMC() + blockSize := hasher.BlockSize() + for i := 0; i < len(data); i += 32 { + d := data[i : i+32] + // ensure the input to hasher.Write is smaller than the curve modulus, + // otherwise hasher.Write will fail + n := new(big.Int).SetBytes(d) + n.Mod(n, bls12_381fr.Modulus()) + d = n.Bytes() + if len(d) < blockSize { + d = n.FillBytes(make([]byte, blockSize)) + } + hasher.Write(d) + } + hv := make([]byte, 0, hasher.Size()) + hv = hasher.Sum(hv) + cx.Stack[last].Bytes = hv + return nil +} + +// mimc on curve BN254 is implemented for compatibility with zk circuits, +// matching the implementation in circuits generated by gnark +func opMimcBN254(cx *EvalContext) error { + last := len(cx.Stack) - 1 + data := cx.Stack[last].Bytes + if len(data)%32 != 0 { + return fmt.Errorf("the input data must be a multiple of 32 bytes") + } + hasher := bn254mimc.NewMiMC() + blockSize := hasher.BlockSize() + for i := 0; i < len(data); i += 32 { + d := data[i : i+32] + // ensure the input to hasher.Write is smaller than the curve modulus, + // otherwise hasher.Write will fail + n := new(big.Int).SetBytes(d) + n.Mod(n, bn254fr.Modulus()) + d = n.Bytes() + if len(d) < blockSize { + d = n.FillBytes(make([]byte, blockSize)) + } + hasher.Write(d) + } + hv := make([]byte, 0, hasher.Size()) + hv = hasher.Sum(hv) + cx.Stack[last].Bytes = hv + return nil +} + func opSHA256(cx *EvalContext) error { last := len(cx.Stack) - 1 hash := sha256.Sum256(cx.Stack[last].Bytes) diff --git a/data/transactions/logic/crypto_test.go b/data/transactions/logic/crypto_test.go index 5aad230289..214adef8b2 100644 --- a/data/transactions/logic/crypto_test.go +++ b/data/transactions/logic/crypto_test.go @@ -713,7 +713,7 @@ int ` + fmt.Sprintf("%d", testLogicBudget-2500-8) + ` } func BenchmarkHashes(b *testing.B) { - for _, hash := range []string{"sha256", "keccak256" /* skip, same as keccak "sha3_256", */, "sha512_256", "sumhash512"} { + for _, hash := range []string{"sha256", "keccak256" /* skip, same as keccak "sha3_256", */, "sha512_256", "sumhash512", "mimc_BN254", "mimc_BLS12_381"} { for _, size := range []int{0, 32, 128, 512, 1024, 4096} { b.Run(hash+"-"+strconv.Itoa(size), func(b *testing.B) { benchmarkOperation(b, "", fmt.Sprintf("int %d; bzero; %s; pop", size, hash), "int 1") diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index fde870a9d4..84f846eddb 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -41,6 +41,13 @@ var opDescByName = map[string]OpDesc{ "sumhash512": {"sumhash512 of value A, yields [64]byte", "", nil}, "falcon_verify": {"for (data A, compressed-format signature B, pubkey C) verify the signature of data against the pubkey", "", nil}, + "mimc_BN254": {"MIMC hash of value A in the BN254 curve field, yields [32]byte", + "A is split into 32-byte chunks, each reduced by the curve modulus, and written to the hasher to finally compute the MiMC hash. Fail if A's length is not a multiple of 32", nil, + }, + "mimc_BLS12_381": {"MIMC hash of value A in the BLS12-381 curve field, yields [32]byte", + "A is split into 32-byte chunks, each reduced by the curve modulus, and written to the hasher to finally compute the MiMC hash. Fail if A's length is not a multiple of 32", nil, + }, + "ed25519verify": {"for (data A, signature B, pubkey C) verify the signature of (\"ProgData\" || program_hash || data) against the pubkey => {0 or 1}", "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.", nil}, "ed25519verify_bare": {"for (data A, signature B, pubkey C) verify the signature of the data against the pubkey => {0 or 1}", "", nil}, "ecdsa_verify": {"for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1}", "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.", []string{"curve index"}}, @@ -352,7 +359,7 @@ var OpGroups = map[string][]string{ "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 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"}, + "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", "mimc_BN254", "mimc_BLS12_381"}, "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"}, "Flow Control": {"err", "bnz", "bz", "b", "return", "pop", "popn", "dup", "dup2", "dupn", "dig", "bury", "cover", "uncover", "frame_dig", "frame_bury", "swap", "select", "assert", "callsub", "proto", "retsub", "switch", "match"}, "State Access": {"balance", "min_balance", "app_opted_in", "app_local_get", "app_local_get_ex", "app_global_get", "app_global_get_ex", "app_local_put", "app_global_put", "app_local_del", "app_global_del", "asset_holding_get", "asset_params_get", "app_params_get", "acct_params_get", "log", "block"}, diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 91ad91d1fe..fe2ad59f38 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -3200,6 +3200,10 @@ 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 + + // the mimc_BN254 and mimc_BLS12_381 opcodes require an input size multiple of 32 bytes + "mimc_BN254": ": byte 0x0000000000000000000000000000000000000000000000000000000000000001; mimc_BN254", + "mimc_BLS12_381": ": byte 0x0000000000000000000000000000000000000000000000000000000000000001; mimc_BLS12_381", } /* Make sure the specialCmd tests the opcode in question */ diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index b8ecd76cac..64ce702234 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -793,6 +793,9 @@ var OpSpecs = []OpSpec{ costByField("g", &EcGroups, []int{ BN254g1: 630, BN254g2: 3_300, BLS12_381g1: 1_950, BLS12_381g2: 8_150})}, + + {0xf0, "mimc_BN254", opMimcBN254, proto("b:b{32}"), 11, costByLength(1, 620, 32, 0)}, + {0xf1, "mimc_BLS12_381", opMimcBLS12381, proto("b:b{32}"), 11, costByLength(1, 620, 32, 0)}, } // 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 915957f7f0..2c788d99ed 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%|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|mimc_BLS12_381|mimc_BN254|sha256|sha3_256|sha512_256|sumhash512|vrf_verify|gitxn|gitxna|gitxnas|itxn|itxn_begin|itxn_field|itxn_next|itxn_submit|itxna|itxnas)\\b" } ] }, From d44a8a7153446fdeeea10e5d85016b369809d679 Mon Sep 17 00:00:00 2001 From: John Jannotti Date: Tue, 14 May 2024 12:27:49 -0400 Subject: [PATCH 2/5] Make mimc a single opcode It's a little ugly to re-use the ec constants, maybe that should be changed. This also changes the opcode to panic on buffers than contain elements greater than the curve's modulus. It's unclear what mimc should do with a zero buffer. Even gnark seems unsure. Their code says: ``` // TODO @ThomasPiellard shouldn't Sum() returns an error if there is no data? // TODO: @Tabaie, @Thomas Piellard Now sure what to make of this /*if len(d.data) == 0 { d.data = make([]byte, BlockSize) }*/ ``` --- data/transactions/logic/assembler_test.go | 15 ++-- data/transactions/logic/crypto.go | 72 +++++++------------- data/transactions/logic/crypto_test.go | 2 +- data/transactions/logic/doc.go | 9 +-- data/transactions/logic/evalStateful_test.go | 5 +- data/transactions/logic/opcodes.go | 25 ++++++- 6 files changed, 59 insertions(+), 69 deletions(-) diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 4b2966a529..41962bb933 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -434,13 +434,9 @@ dup; dup falcon_verify ` -const mimcBN254Nonsense = ` +const mimcNonsense = ` pushbytes 0x11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff -mimc_BN254 -` -const mimcBLS12381Nonsense = ` -pushbytes 0x11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff -mimc_BLS12_381 +mimc BLS12_381g1 ` const v8Nonsense = v7Nonsense + switchNonsense + frameNonsense + matchNonsense + boxNonsense @@ -454,7 +450,7 @@ const spliceNonsence = ` const v10Nonsense = v9Nonsense + pairingNonsense + spliceNonsence -const v11Nonsense = v10Nonsense + stateProofNonsense + mimcBN254Nonsense + mimcBLS12381Nonsense +const v11Nonsense = v10Nonsense + stateProofNonsense + mimcNonsense const v6Compiled = "2004010002b7a60c26050242420c68656c6c6f20776f726c6421070123456789abcd208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292b0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f2310231123122313231418191a1b1c28171615400003290349483403350222231d4a484848482b50512a632223524100034200004322602261222704634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f447825225314225427042455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f012a57000823810858235b235a2359b03139330039b1b200b322c01a23c1001a2323c21a23c3233e233f8120af06002a494905002a49490700b400b53a03b6b7043cb8033a0c2349c42a9631007300810881088120978101c53a8101c6003a" @@ -477,10 +473,9 @@ const spliceCompiled = "d2d3" const v10Compiled = v9Compiled + pairingCompiled + spliceCompiled const stateProofCompiled = "80070123456789abcd86494985" -const mimcBN254Compiled = "802011223344556677889900aabbccddeeff11223344556677889900aabbccddeefff0" -const mimcBLS12381Compiled = "802011223344556677889900aabbccddeeff11223344556677889900aabbccddeefff1" +const mimcCompiled = "802011223344556677889900aabbccddeeff11223344556677889900aabbccddeeffe602" -const V11Compiled = v10Compiled + stateProofCompiled + mimcBN254Compiled + mimcBLS12381Compiled +const V11Compiled = v10Compiled + stateProofCompiled + mimcCompiled var nonsense = map[uint64]string{ 1: v1Nonsense, diff --git a/data/transactions/logic/crypto.go b/data/transactions/logic/crypto.go index cd67ecdcc5..829bc35c8c 100644 --- a/data/transactions/logic/crypto.go +++ b/data/transactions/logic/crypto.go @@ -23,6 +23,7 @@ import ( "crypto/sha512" "errors" "fmt" + "hash" "math/big" "github.com/algorand/go-algorand/crypto" @@ -31,65 +32,44 @@ import ( "github.com/algorand/go-sumhash" "golang.org/x/crypto/sha3" - bls12_381fr "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" bls12_381mimc "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/mimc" - bn254fr "github.com/consensys/gnark-crypto/ecc/bn254/fr" bn254mimc "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" ) -// mimc on curve BLS12-381 is implemented for compatibility with zk circuits, +// mimc is implemented for compatibility with zk circuits, // matching the implementation in circuits generated by gnark -func opMimcBLS12381(cx *EvalContext) error { - last := len(cx.Stack) - 1 - data := cx.Stack[last].Bytes - if len(data)%32 != 0 { - return fmt.Errorf("the input data must be a multiple of 32 bytes") - } - hasher := bls12_381mimc.NewMiMC() - blockSize := hasher.BlockSize() - for i := 0; i < len(data); i += 32 { - d := data[i : i+32] - // ensure the input to hasher.Write is smaller than the curve modulus, - // otherwise hasher.Write will fail - n := new(big.Int).SetBytes(d) - n.Mod(n, bls12_381fr.Modulus()) - d = n.Bytes() - if len(d) < blockSize { - d = n.FillBytes(make([]byte, blockSize)) - } - hasher.Write(d) +func opMimc(cx *EvalContext) error { + group := EcGroup(cx.program[cx.pc+1]) + fs, ok := ecGroupSpecByField(group) + if !ok { // no version check yet, all groups appeared at once + return fmt.Errorf("invalid mimc group %s", group) } - hv := make([]byte, 0, hasher.Size()) - hv = hasher.Sum(hv) - cx.Stack[last].Bytes = hv - return nil -} -// mimc on curve BN254 is implemented for compatibility with zk circuits, -// matching the implementation in circuits generated by gnark -func opMimcBN254(cx *EvalContext) error { last := len(cx.Stack) - 1 data := cx.Stack[last].Bytes if len(data)%32 != 0 { return fmt.Errorf("the input data must be a multiple of 32 bytes") } - hasher := bn254mimc.NewMiMC() - blockSize := hasher.BlockSize() - for i := 0; i < len(data); i += 32 { - d := data[i : i+32] - // ensure the input to hasher.Write is smaller than the curve modulus, - // otherwise hasher.Write will fail - n := new(big.Int).SetBytes(d) - n.Mod(n, bn254fr.Modulus()) - d = n.Bytes() - if len(d) < blockSize { - d = n.FillBytes(make([]byte, blockSize)) - } - hasher.Write(d) + + var mimc hash.Hash + + switch fs.field { + case BN254g1, BN254g2: + mimc = bn254mimc.NewMiMC() + case BLS12_381g1, BLS12_381g2: + mimc = bls12_381mimc.NewMiMC() + default: + return fmt.Errorf("invalid mimc group %s", group) } - hv := make([]byte, 0, hasher.Size()) - hv = hasher.Sum(hv) - cx.Stack[last].Bytes = hv + + // unlike most hash.Hash objects, a mimc hasher has strict requirements. The + // input must be a multiple of the curve's encoded element size, and no + // element may exceed the corve modulus. + if _, err := mimc.Write(cx.Stack[last].Bytes); err != nil { + return fmt.Errorf("invalid mimc input %w", err) + } + + cx.Stack[last].Bytes = mimc.Sum(nil) return nil } diff --git a/data/transactions/logic/crypto_test.go b/data/transactions/logic/crypto_test.go index 214adef8b2..4f4856c098 100644 --- a/data/transactions/logic/crypto_test.go +++ b/data/transactions/logic/crypto_test.go @@ -713,7 +713,7 @@ int ` + fmt.Sprintf("%d", testLogicBudget-2500-8) + ` } func BenchmarkHashes(b *testing.B) { - for _, hash := range []string{"sha256", "keccak256" /* skip, same as keccak "sha3_256", */, "sha512_256", "sumhash512", "mimc_BN254", "mimc_BLS12_381"} { + for _, hash := range []string{"sha256", "keccak256" /* skip, same as keccak "sha3_256", */, "sha512_256", "sumhash512", "mimc BN254g1", "mimc BLS12_381g1"} { for _, size := range []int{0, 32, 128, 512, 1024, 4096} { b.Run(hash+"-"+strconv.Itoa(size), func(b *testing.B) { benchmarkOperation(b, "", fmt.Sprintf("int %d; bzero; %s; pop", size, hash), "int 1") diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index 84f846eddb..431c5e030b 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -41,11 +41,8 @@ var opDescByName = map[string]OpDesc{ "sumhash512": {"sumhash512 of value A, yields [64]byte", "", nil}, "falcon_verify": {"for (data A, compressed-format signature B, pubkey C) verify the signature of data against the pubkey", "", nil}, - "mimc_BN254": {"MIMC hash of value A in the BN254 curve field, yields [32]byte", - "A is split into 32-byte chunks, each reduced by the curve modulus, and written to the hasher to finally compute the MiMC hash. Fail if A's length is not a multiple of 32", nil, - }, - "mimc_BLS12_381": {"MIMC hash of value A in the BLS12-381 curve field, yields [32]byte", - "A is split into 32-byte chunks, each reduced by the curve modulus, and written to the hasher to finally compute the MiMC hash. Fail if A's length is not a multiple of 32", nil, + "mimc": {"MIMC hash of value A in the curve field G, yields [32]byte", + "A is split into 32-byte chunks and written to the hasher to finally compute the MiMC hash. Fail if A's length is not a multiple of 32 or any chunk encodes a value greater than the curve modulus", []string{"curve index"}, }, "ed25519verify": {"for (data A, signature B, pubkey C) verify the signature of (\"ProgData\" || program_hash || data) against the pubkey => {0 or 1}", "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.", nil}, @@ -359,7 +356,7 @@ var OpGroups = map[string][]string{ "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 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", "mimc_BN254", "mimc_BLS12_381"}, + "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", "mimc"}, "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"}, "Flow Control": {"err", "bnz", "bz", "b", "return", "pop", "popn", "dup", "dup2", "dupn", "dig", "bury", "cover", "uncover", "frame_dig", "frame_bury", "swap", "select", "assert", "callsub", "proto", "retsub", "switch", "match"}, "State Access": {"balance", "min_balance", "app_opted_in", "app_local_get", "app_local_get_ex", "app_global_get", "app_global_get_ex", "app_local_put", "app_global_put", "app_local_del", "app_global_del", "asset_holding_get", "asset_params_get", "app_params_get", "acct_params_get", "log", "block"}, diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index fe2ad59f38..688988bec0 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -3201,9 +3201,8 @@ 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 - // the mimc_BN254 and mimc_BLS12_381 opcodes require an input size multiple of 32 bytes - "mimc_BN254": ": byte 0x0000000000000000000000000000000000000000000000000000000000000001; mimc_BN254", - "mimc_BLS12_381": ": byte 0x0000000000000000000000000000000000000000000000000000000000000001; mimc_BLS12_381", + // mimc requires an input size multiple of 32 bytes. + "mimc": ": byte 0x0000000000000000000000000000000000000000000000000000000000000001; mimc BN254g1", } /* Make sure the specialCmd tests the opcode in question */ diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index 64ce702234..47ccf0bae2 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -78,6 +78,7 @@ const pairingVersion = 10 // bn256 opcodes. will add bls12-381, and unify the av const spliceVersion = 10 // box splicing/resizing const spOpcodesVersion = 11 // falcon_verify, sumhash512 +const mimcVersion = 11 // Unlimited Global Storage opcodes const boxVersion = 8 // box_* @@ -793,9 +794,27 @@ var OpSpecs = []OpSpec{ costByField("g", &EcGroups, []int{ BN254g1: 630, BN254g2: 3_300, BLS12_381g1: 1_950, BLS12_381g2: 8_150})}, - - {0xf0, "mimc_BN254", opMimcBN254, proto("b:b{32}"), 11, costByLength(1, 620, 32, 0)}, - {0xf1, "mimc_BLS12_381", opMimcBLS12381, proto("b:b{32}"), 11, costByLength(1, 620, 32, 0)}, + {0xe6, "mimc", opMimc, proto("b:b{32}"), mimcVersion, costByFieldAndLength("g", &EcGroups, []linearCost{ + BN254g1: { + baseCost: 10, + chunkCost: 650, + chunkSize: 32, + }, + BN254g2: { + baseCost: 10, + chunkCost: 650, + chunkSize: 32, + }, + BLS12_381g1: { + baseCost: 10, + chunkCost: 650, + chunkSize: 32, + }, + BLS12_381g2: { + baseCost: 10, + chunkCost: 650, + chunkSize: 32, + }})}, } // OpcodesByVersion returns list of opcodes available in a specific version of TEAL From 3979001541cd65edf79185d22402c58760ced0e2 Mon Sep 17 00:00:00 2001 From: giulio Date: Wed, 15 May 2024 16:05:39 +0200 Subject: [PATCH 3/5] Make mimc fail on empty input and add test vectors --- data/transactions/logic/crypto.go | 3 + data/transactions/logic/crypto_test.go | 69 ++++++++++++++++++++ data/transactions/logic/teal.tmLanguage.json | 2 +- 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/data/transactions/logic/crypto.go b/data/transactions/logic/crypto.go index 829bc35c8c..b7c3be1cd0 100644 --- a/data/transactions/logic/crypto.go +++ b/data/transactions/logic/crypto.go @@ -47,6 +47,9 @@ func opMimc(cx *EvalContext) error { last := len(cx.Stack) - 1 data := cx.Stack[last].Bytes + if len(data) == 0 { + return fmt.Errorf("the input data cannot be empty") + } if len(data)%32 != 0 { return fmt.Errorf("the input data must be a multiple of 32 bytes") } diff --git a/data/transactions/logic/crypto_test.go b/data/transactions/logic/crypto_test.go index 4f4856c098..5f211e4ba9 100644 --- a/data/transactions/logic/crypto_test.go +++ b/data/transactions/logic/crypto_test.go @@ -117,6 +117,72 @@ byte 0x98D2C31612EA500279B6753E5F6E780CA63EBA8274049664DAD66A2565ED1D2A testAccepts(t, progText, 1) } +func TestMimc(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + // Test vectors from https://github.com/giuliop/test-mimc-opcodes/blob/main/testcases/circuit.go + // generated by instantiating a zk-circuit that processes MiMC hash of the preimages. + // We test success for 32-byte and 96-byte preimages, and failure for preimage input size of 0, + // input size not multiple of 32 bytes, and chunks representing values greater than the modulus. + + preImageTestVectors := []string{ + // FAIL: zero-length + "0x", + // SUCCEED: 32 bytes, less than modulus + "0x23a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b5042535", + // FAIL: 32 bytes, more than modulus + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", + // FAIL: less than 32 byte + "0xdeadf00d", + // SUCCEED: 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, less than modulus + "0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b504253530644e72e131a029b85045b68181585d2833e84879b9709143e1f593ef676981", + // FAIL: 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, more than modulus + "0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b504253573eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", + // FAIL: 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, more than modulus + "0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b5042535abba", + } + circuitHashTestVectors := map[string][]string{ + "BN254": { + "20104241803663641422577121134203490505137011783614913652735802145961801733870", + "12886436712380113721405259596386800092738845035233065858332878701083870690753", + "19565877911319815535452130675266047290072088868113536892077808700068649624391", + "1037254799353855871006189384309576393135431139055333626960622147300727796413", + "6040222623731283351958201178122781676432899642144860863024149088913741383362", + "21691351735381703396517600859480938764038501053226864452091917666642352837076", + "10501393540371963307040960561318023073151272109639330842515119353134949995409", + }, + "BLS12_381": { + "17991912493598890696181760734961918471863781118188078948205844982816313445306", + "8791766422525455185980675814845076441443662947059416063736889106252015893524", + "35137972692771717943992759113612269767581262500164574105059686144346651628747", + "15039173432183897369859775531867817848264266283034981501223857291379142522368", + "12964111614552580241101202600014316932811348627866250816177200046290462797607", + "21773894974440411325489312534417904228129169539217646609523079291104496302656", + "9873666029497961930790892458408217321483390383568592297687427911011295910871", + }, + } + shouldSucceed := []bool{false, true, false, false, true, false, false} + + for _, curve := range []string{"BN254", "BLS12_381"} { + for i, preImage := range preImageTestVectors { + var n big.Int + n.SetString(circuitHashTestVectors[curve][i], 10) + circuitHash := n.Bytes() + progText := fmt.Sprintf(`byte %s +mimc %sg1 + +byte 0x%x +==`, preImage, curve, circuitHash) + if shouldSucceed[i] { + testAccepts(t, progText, 11) + } else { + testPanics(t, progText, 11) + } + } + } +} + // This is patterned off vrf_test.go, but we don't create proofs here, we only // check that the output is correct, given the proof. func testVrfApp(pubkey, proof, data string, output string) string { @@ -715,6 +781,9 @@ int ` + fmt.Sprintf("%d", testLogicBudget-2500-8) + ` func BenchmarkHashes(b *testing.B) { for _, hash := range []string{"sha256", "keccak256" /* skip, same as keccak "sha3_256", */, "sha512_256", "sumhash512", "mimc BN254g1", "mimc BLS12_381g1"} { for _, size := range []int{0, 32, 128, 512, 1024, 4096} { + if size == 0 && (hash == "mimc BN254g1" || hash == "mimc BLS12_381g1") { + continue + } b.Run(hash+"-"+strconv.Itoa(size), func(b *testing.B) { benchmarkOperation(b, "", fmt.Sprintf("int %d; bzero; %s; pop", size, hash), "int 1") }) diff --git a/data/transactions/logic/teal.tmLanguage.json b/data/transactions/logic/teal.tmLanguage.json index 2c788d99ed..82e2e45f6d 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|mimc_BLS12_381|mimc_BN254|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%|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|mimc|sha256|sha3_256|sha512_256|sumhash512|vrf_verify|gitxn|gitxna|gitxnas|itxn|itxn_begin|itxn_field|itxn_next|itxn_submit|itxna|itxnas)\\b" } ] }, From ad777e38b54b3c1ff92e6f43ce162a135322ade7 Mon Sep 17 00:00:00 2001 From: giulio Date: Wed, 15 May 2024 22:46:33 +0200 Subject: [PATCH 4/5] Add mimcVersion to experiments and improve tests --- data/transactions/logic/assembler_test.go | 2 +- data/transactions/logic/crypto_test.go | 42 +++++++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index ce6fc251a1..fa89255d0d 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -556,7 +556,7 @@ func TestAssemble(t *testing.T) { } } -var experiments = []uint64{spOpcodesVersion} +var experiments = []uint64{spOpcodesVersion, mimcVersion} // 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/crypto_test.go b/data/transactions/logic/crypto_test.go index 5f211e4ba9..62116b8a12 100644 --- a/data/transactions/logic/crypto_test.go +++ b/data/transactions/logic/crypto_test.go @@ -126,22 +126,27 @@ func TestMimc(t *testing.T) { // We test success for 32-byte and 96-byte preimages, and failure for preimage input size of 0, // input size not multiple of 32 bytes, and chunks representing values greater than the modulus. - preImageTestVectors := []string{ - // FAIL: zero-length - "0x", - // SUCCEED: 32 bytes, less than modulus - "0x23a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b5042535", - // FAIL: 32 bytes, more than modulus - "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", - // FAIL: less than 32 byte - "0xdeadf00d", - // SUCCEED: 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, less than modulus - "0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b504253530644e72e131a029b85045b68181585d2833e84879b9709143e1f593ef676981", - // FAIL: 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, more than modulus - "0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b504253573eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", - // FAIL: 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, more than modulus - "0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b5042535abba", + type PreImageTestVector struct { + PreImage string + ShouldSucceed bool } + preImageTestVectors := []PreImageTestVector{ + {"0x", + false}, // zero-length input + {"0x23a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b5042535", + true}, // 32 bytes, less than modulus + {"0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", + false}, // 32 bytes, more than modulus + {"0xdeadf00d", + false}, // less than 32 byte + {"0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b504253530644e72e131a029b85045b68181585d2833e84879b9709143e1f593ef676981", + true}, // 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, less than modulus + {"0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b504253573eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002", + false}, // 32 bytes, less than modulus | 32 bytes, less than modulus | 32 bytes, more than modulus + {"0x183de351a72141d79c51a27d10405549c98302cb2536c5968deeb3cba635121723a950068dd3d1e21cee48e7919be7ae32cdef70311fc486336ea9d4b5042535abba", + false}, // 32 bytes, less than modulus | 32 bytes, less than modulus | less than 32 bytes + } + circuitHashTestVectors := map[string][]string{ "BN254": { "20104241803663641422577121134203490505137011783614913652735802145961801733870", @@ -162,10 +167,9 @@ func TestMimc(t *testing.T) { "9873666029497961930790892458408217321483390383568592297687427911011295910871", }, } - shouldSucceed := []bool{false, true, false, false, true, false, false} for _, curve := range []string{"BN254", "BLS12_381"} { - for i, preImage := range preImageTestVectors { + for i, preImageTestVector := range preImageTestVectors { var n big.Int n.SetString(circuitHashTestVectors[curve][i], 10) circuitHash := n.Bytes() @@ -173,8 +177,8 @@ func TestMimc(t *testing.T) { mimc %sg1 byte 0x%x -==`, preImage, curve, circuitHash) - if shouldSucceed[i] { +==`, preImageTestVector.PreImage, curve, circuitHash) + if preImageTestVector.ShouldSucceed { testAccepts(t, progText, 11) } else { testPanics(t, progText, 11) From 2de29ea7e95164a6c60f3bc90553ef0bf458fb0b Mon Sep 17 00:00:00 2001 From: giulio Date: Thu, 16 May 2024 17:26:08 +0200 Subject: [PATCH 5/5] Correct link to mimc test cases --- data/transactions/logic/crypto_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/transactions/logic/crypto_test.go b/data/transactions/logic/crypto_test.go index 62116b8a12..d464b20313 100644 --- a/data/transactions/logic/crypto_test.go +++ b/data/transactions/logic/crypto_test.go @@ -121,7 +121,7 @@ func TestMimc(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - // Test vectors from https://github.com/giuliop/test-mimc-opcodes/blob/main/testcases/circuit.go + // Test vectors from https://github.com/giuliop/test-mimc-opcodes/blob/main/mimctest/main.go // generated by instantiating a zk-circuit that processes MiMC hash of the preimages. // We test success for 32-byte and 96-byte preimages, and failure for preimage input size of 0, // input size not multiple of 32 bytes, and chunks representing values greater than the modulus.