From 7224872a62032b8990bee62445eba7999218c34f Mon Sep 17 00:00:00 2001 From: Emanuele Cesena Date: Thu, 16 May 2024 20:22:19 +0000 Subject: [PATCH] add syscall secp256k1 --- generators/secp256k1.py | 4 +- generators/syscalls_hash.py | 44 +++---- generators/syscalls_poseidon.py | 67 +++++----- generators/syscalls_secp256k1.py | 206 +++++++++++++++++++++++++++++++ impl/agave-v1.17 | 1 - impl/agave-v2.0 | 2 +- impl/firedancer | 1 - install.sh | 4 +- 8 files changed, 267 insertions(+), 62 deletions(-) create mode 100644 generators/syscalls_secp256k1.py delete mode 160000 impl/agave-v1.17 mode change 160000 => 120000 impl/agave-v2.0 delete mode 160000 impl/firedancer diff --git a/generators/secp256k1.py b/generators/secp256k1.py index bce96f4..58684e6 100644 --- a/generators/secp256k1.py +++ b/generators/secp256k1.py @@ -67,8 +67,8 @@ # tested above # https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L975-L978 # signature fails to decode - [1, 32, 0, 0, 12, 0, 0, 97, 0, 5, 0, 0, 129, 246, 169, 169, 105, 76, 208, 128, 223, 135, 27, 68, 249, 42, 201, 69, 55, 2, 173, 101, 255, 196, 198, 193, 237, 0, 14, 83, 87, 183, 25, 69, 136, 43, 251, 73, 44, 194, 141, 230, 102, 16, 220, 6, 46, 214, 214, 125, 120, 16, 103, 254, 39, 121, 88, 223, 156, 229, 186, 211, 38, 101, 196, 233, 125, 150, 136, 177, 123, 197, 48, 219, 28, 26, 10, 76, 198, 127, 91, 80, 88, 191, 6, 3, 255, 104, 101, 108, 108, 111], - # \--- pubkey (eth) ---/ \--- sig ---/ \--- msg ---/ + [1, 32, 0, 0, 12, 0, 0, 97, 0, 5, 0, 0, 129, 246, 169, 169, 105, 76, 208, 128, 223, 135, 27, 68, 249, 42, 201, 69, 55, 2, 173, 101, 255, 196, 198, 193, 237, 0, 14, 83, 87, 183, 25, 69, 136, 43, 251, 73, 44, 194, 141, 230, 102, 16, 220, 6, 46, 214, 214, 125, 120, 16, 103, 254, 39, 121, 88, 223, 156, 229, 186, 211, 38, 101, 196, 233, 125, 150, 136, 177, 123, 197, 48, 219, 28, 26, 10, 76, 198, 127, 91, 80, 88, 191, 6, 3, 1, 104, 101, 108, 108, 111], + # \--- pubkey (eth) ---/ \--- sig ---/ \--- msg ---/ # InvalidRecoveryId (result: 2) # https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L981C43-L981C60 diff --git a/generators/syscalls_hash.py b/generators/syscalls_hash.py index ea776df..77456ce 100644 --- a/generators/syscalls_hash.py +++ b/generators/syscalls_hash.py @@ -1,6 +1,5 @@ import hashlib import test_suite.vm_pb2 as pbvm -from dataclasses import dataclass import struct OUTPUT_DIR = "./test-vectors/instr/inputs/20240425/syscalls" @@ -179,30 +178,31 @@ def exact_cu_cost(data_vec): def _into_key_data(key_prefix, test_vectors): return [(key_prefix + str(j), data) for j, data in enumerate(test_vectors)] -print("Generating syscalls sha256, keccak256, blake3 tests...") - test_vectors = _into_key_data("h", test_vectors_hash) -for (key, test) in test_vectors: - for hash in ["sha256", "keccak256", "blake3"]: - heap_prefix = test.get("heap_prefix", []) - syscall_ctx = pbvm.SyscallContext() - syscall_ctx.syscall_invocation.function_name = bytes("sol_" + hash, "ascii") - syscall_ctx.syscall_invocation.heap_prefix = bytes(heap_prefix) - syscall_ctx.vm_ctx.heap_max = len(heap_prefix) - syscall_ctx.vm_ctx.r1 = test.get("vals_addr", 0) - syscall_ctx.vm_ctx.r2 = test.get("vals_len", 0) - syscall_ctx.vm_ctx.r3 = test.get("result_addr", 0) - syscall_ctx.instr_ctx.cu_avail = test.get("cu_avail", 0) - syscall_ctx.instr_ctx.program_id = bytes([0]*32) # solfuzz-agave expectes a program_id - syscall_ctx.vm_ctx.rodata = b"x" # fd expects some bytes +if __name__ == "__main__": + print("Generating syscalls sha256, keccak256, blake3 tests...") + + for (key, test) in test_vectors: + for hash in ["sha256", "keccak256", "blake3"]: + heap_prefix = test.get("heap_prefix", []) + syscall_ctx = pbvm.SyscallContext() + syscall_ctx.syscall_invocation.function_name = bytes("sol_" + hash, "ascii") + syscall_ctx.syscall_invocation.heap_prefix = bytes(heap_prefix) + syscall_ctx.vm_ctx.heap_max = len(heap_prefix) + syscall_ctx.vm_ctx.r1 = test.get("vals_addr", 0) + syscall_ctx.vm_ctx.r2 = test.get("vals_len", 0) + syscall_ctx.vm_ctx.r3 = test.get("result_addr", 0) + syscall_ctx.instr_ctx.cu_avail = test.get("cu_avail", 0) + syscall_ctx.instr_ctx.program_id = bytes([0]*32) # solfuzz-agave expectes a program_id + syscall_ctx.vm_ctx.rodata = b"x" # fd expects some bytes - syscall_ctx.instr_ctx.epoch_context.features.features.extend([0xe994a4b8eeea84f4]) # enable blake3 + syscall_ctx.instr_ctx.epoch_context.features.features.extend([0xe994a4b8eeea84f4]) # enable blake3 - filename = str(key) + "_" + hashlib.sha3_256(syscall_ctx.instr_ctx.data).hexdigest()[:16] + filename = str(key) + "_" + hashlib.sha3_256(syscall_ctx.instr_ctx.data).hexdigest()[:16] - serialized_instr = syscall_ctx.SerializeToString(deterministic=True) - with open(f"{OUTPUT_DIR}/{hash}/{filename}.bin", "wb") as f: - f.write(serialized_instr) + serialized_instr = syscall_ctx.SerializeToString(deterministic=True) + with open(f"{OUTPUT_DIR}/{hash}/{filename}.bin", "wb") as f: + f.write(serialized_instr) -print("done!") + print("done!") diff --git a/generators/syscalls_poseidon.py b/generators/syscalls_poseidon.py index 45b6c7e..d0e1295 100644 --- a/generators/syscalls_poseidon.py +++ b/generators/syscalls_poseidon.py @@ -1,7 +1,5 @@ import hashlib import test_suite.vm_pb2 as pbvm -from dataclasses import dataclass -import struct from syscalls_hash import test_vectors as test_vectors_hash, heap_vec OUTPUT_DIR = "./test-vectors/instr/inputs/20240425/syscalls/poseidon" @@ -190,34 +188,37 @@ def _into_key_data(key_prefix, test_vectors): # these are all the tests in test_vectors_poseidon ] -print("Generating syscall poseidon tests...") - -test_vectors = _into_key_data("p", test_vectors_poseidon) + _into_key_data("w", test_vectors_workflow) + test_vectors_hash - -for (key, test) in test_vectors: - heap_prefix = test.get("heap_prefix", []) - syscall_ctx = pbvm.SyscallContext() - syscall_ctx.syscall_invocation.function_name = b"sol_poseidon" - syscall_ctx.syscall_invocation.heap_prefix = bytes(heap_prefix) - syscall_ctx.vm_ctx.heap_max = len(heap_prefix) - syscall_ctx.vm_ctx.r1 = test.get("params", 0) - syscall_ctx.vm_ctx.r2 = test.get("endianness", 0) - syscall_ctx.vm_ctx.r3 = test.get("vals_addr", 0) - syscall_ctx.vm_ctx.r4 = test.get("vals_len", 0) - syscall_ctx.vm_ctx.r5 = test.get("result_addr", 0) - syscall_ctx.instr_ctx.cu_avail = test.get("cu_avail", 0) - syscall_ctx.instr_ctx.program_id = bytes([0]*32) # solfuzz-agave expectes a program_id - syscall_ctx.vm_ctx.rodata = b"x" # fd expects some bytes - - syscall_ctx.instr_ctx.epoch_context.features.features.extend([ - 0x3cbf822ccb2eebd4, # enable_poseidon_syscall - 0x8ba9e9038d9fdcff, # simplify_alt_bn128_syscall_error_codes - ]) - - filename = str(key) + "_" + hashlib.sha3_256(syscall_ctx.instr_ctx.data).hexdigest()[:16] - - serialized_instr = syscall_ctx.SerializeToString(deterministic=True) - with open(f"{OUTPUT_DIR}/{filename}.bin", "wb") as f: - f.write(serialized_instr) - -print("done!") +test_vectors = _into_key_data("p", test_vectors_poseidon) \ + + _into_key_data("w", test_vectors_workflow) \ + + test_vectors_hash + +if __name__ == "__main__": + print("Generating syscall poseidon tests...") + + for (key, test) in test_vectors: + heap_prefix = test.get("heap_prefix", []) + syscall_ctx = pbvm.SyscallContext() + syscall_ctx.syscall_invocation.function_name = b"sol_poseidon" + syscall_ctx.syscall_invocation.heap_prefix = bytes(heap_prefix) + syscall_ctx.vm_ctx.heap_max = len(heap_prefix) + syscall_ctx.vm_ctx.r1 = test.get("params", 0) + syscall_ctx.vm_ctx.r2 = test.get("endianness", 0) + syscall_ctx.vm_ctx.r3 = test.get("vals_addr", 0) + syscall_ctx.vm_ctx.r4 = test.get("vals_len", 0) + syscall_ctx.vm_ctx.r5 = test.get("result_addr", 0) + syscall_ctx.instr_ctx.cu_avail = test.get("cu_avail", 0) + syscall_ctx.instr_ctx.program_id = bytes([0]*32) # solfuzz-agave expectes a program_id + syscall_ctx.vm_ctx.rodata = b"x" # fd expects some bytes + + syscall_ctx.instr_ctx.epoch_context.features.features.extend([ + 0x3cbf822ccb2eebd4, # enable_poseidon_syscall + # 0x8ba9e9038d9fdcff, # simplify_alt_bn128_syscall_error_codes + ]) + + filename = str(key) + "_" + hashlib.sha3_256(syscall_ctx.instr_ctx.data).hexdigest()[:16] + + serialized_instr = syscall_ctx.SerializeToString(deterministic=True) + with open(f"{OUTPUT_DIR}/{filename}.bin", "wb") as f: + f.write(serialized_instr) + + print("done!") diff --git a/generators/syscalls_secp256k1.py b/generators/syscalls_secp256k1.py new file mode 100644 index 0000000..e0052ba --- /dev/null +++ b/generators/syscalls_secp256k1.py @@ -0,0 +1,206 @@ +import hashlib +import test_suite.vm_pb2 as pbvm +from eth_hash.auto import keccak + +OUTPUT_DIR = "./test-vectors/instr/inputs/20240425/syscalls/secp256k1" +HEAP_START = 0x300000000 +CU_BASE = 25_000 + +def _into_key_data(key_prefix, test_vectors): + return [(key_prefix + str(j), data) for j, data in enumerate(test_vectors)] + +pubkey = [129, 246, 169, 169, 105, 76, 208, 128, 223, 135, 27, 68, 249, 42, 201, 69, 55, 2, 173, 101] +sig = [14, 196, 198, 193, 237, 0, 14, 83, 87, 183, 25, 69, 136, 43, 251, 73, 44, 194, 141, 230, 102, 16, 220, 6, 46, 214, 214, 125, 120, 16, 103, 254, 39, 121, 88, 223, 156, 229, 186, 211, 38, 101, 196, 233, 125, 150, 136, 177, 123, 197, 48, 219, 28, 26, 10, 76, 198, 127, 91, 80, 88, 191, 6, 3] +sig_invalid = [255]*64 +sig_err = [14, 196, 198, 193, 237, 0, 14, 255, 87, 183, 25, 69, 136, 43, 251, 73, 44, 194, 141, 230, 102, 16, 220, 6, 46, 214, 214, 125, 120, 16, 103, 254, 39, 121, 88, 223, 156, 229, 186, 211, 38, 101, 196, 233, 125, 150, 136, 177, 123, 197, 48, 219, 28, 26, 10, 76, 198, 127, 91, 80, 88, 191, 6, 3] +# ^^^ modified byte +recid = 1 +msg = [104, 101, 108, 108, 111] # hello +hash = list(keccak(bytes(msg))) + +# all these tests either return Err(.) +test_vectors_workflow = [ + # valid + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + { + "heap_prefix": sig + hash, + "hash_vaddr": HEAP_START + 64, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + { + "heap_prefix": hash + sig, + "hash_vaddr": HEAP_START, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 32, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L820-L821 + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE - 1 + }, + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L823-L828 + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 129, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START - 1, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": 0x500000000, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L829-L834 + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 128, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START -1, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": 0, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L835-L840 + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START + 128, + "cu_avail": CU_BASE + }, + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START - 1, + "cu_avail": CU_BASE + }, + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": 0, + "cu_avail": CU_BASE + }, + + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L842-L844 + # this can never happen + + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L845-L847 + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": 1000, # not a u8 + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L848-L850 + { + "heap_prefix": [0]*64 + sig + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": 4, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L851-L853 + { + "heap_prefix": [0]*64 + sig_invalid + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, + + # https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L858 + { + "heap_prefix": [0]*64 + sig_err + hash, + "hash_vaddr": HEAP_START + 128, + "recovery_id_val": recid, + "signature_vaddr": HEAP_START + 64, + "result_vaddr": HEAP_START, + "cu_avail": CU_BASE + }, +] + +test_vectors = _into_key_data("w", test_vectors_workflow) + +if __name__ == "__main__": + print("Generating syscall secp256k1 tests...") + + for (key, test) in test_vectors: + heap_prefix = test.get("heap_prefix", []) + syscall_ctx = pbvm.SyscallContext() + syscall_ctx.syscall_invocation.function_name = b"sol_secp256k1_recover" + syscall_ctx.syscall_invocation.heap_prefix = bytes(heap_prefix) + syscall_ctx.vm_ctx.heap_max = len(heap_prefix) + syscall_ctx.vm_ctx.r1 = test.get("hash_vaddr", 0) + syscall_ctx.vm_ctx.r2 = test.get("recovery_id_val", 0) + syscall_ctx.vm_ctx.r3 = test.get("signature_vaddr", 0) + syscall_ctx.vm_ctx.r4 = test.get("result_vaddr", 0) + syscall_ctx.instr_ctx.cu_avail = test.get("cu_avail", 0) + syscall_ctx.instr_ctx.program_id = bytes([0]*32) # solfuzz-agave expectes a program_id + syscall_ctx.vm_ctx.rodata = b"x" # fd expects some bytes + + syscall_ctx.instr_ctx.epoch_context.features.features.extend([ + 0x4ab8b2b10003ad50, # secp256k1_recover_syscall_enabled + ]) + + filename = str(key) + "_" + hashlib.sha3_256(syscall_ctx.instr_ctx.data).hexdigest()[:16] + + serialized_instr = syscall_ctx.SerializeToString(deterministic=True) + with open(f"{OUTPUT_DIR}/{filename}.bin", "wb") as f: + f.write(serialized_instr) + + print("done!") diff --git a/impl/agave-v1.17 b/impl/agave-v1.17 deleted file mode 160000 index afe4b01..0000000 --- a/impl/agave-v1.17 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit afe4b0138356cbe0144ab2abc1e39929a651565c diff --git a/impl/agave-v2.0 b/impl/agave-v2.0 deleted file mode 160000 index a7ae268..0000000 --- a/impl/agave-v2.0 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a7ae268adf63fa0f3409dbaf9d3cc0c799716508 diff --git a/impl/agave-v2.0 b/impl/agave-v2.0 new file mode 120000 index 0000000..cb6710e --- /dev/null +++ b/impl/agave-v2.0 @@ -0,0 +1 @@ +/home/ecesena/solfuzz-agave \ No newline at end of file diff --git a/impl/firedancer b/impl/firedancer deleted file mode 160000 index 8e7a55a..0000000 --- a/impl/firedancer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8e7a55a792432c30c643a9bea168f3fcf2e42163 diff --git a/install.sh b/install.sh index 7b5721e..97f57c9 100755 --- a/install.sh +++ b/install.sh @@ -1,8 +1,8 @@ -git submodule init && git submodule update +# git submodule init && git submodule update sudo dnf install -y gcc-toolset-12 || true source /opt/rh/gcc-toolset-12/enable python3.11 -m venv test_suite_env source test_suite_env/bin/activate sudo dnf install -y python3.11-devel || true -make -j -C impl +# make -j -C impl pip install .