diff --git a/Cargo.lock b/Cargo.lock index ce71b932..32e6fd6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,6 +158,22 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -839,10 +855,12 @@ dependencies = [ "interpreter", "itertools", "log", + "num", "plonky2", "rand", "regex", "rocksdb", + "secp256k1 0.28.1", "serde", "serde_derive", "serde_json", @@ -1149,6 +1167,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex-literal" version = "0.3.4" @@ -2370,7 +2394,17 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" dependencies = [ - "secp256k1-sys", + "secp256k1-sys 0.8.1", +] + +[[package]] +name = "secp256k1" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" +dependencies = [ + "bitcoin_hashes", + "secp256k1-sys 0.9.2", ] [[package]] @@ -2382,6 +2416,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -3106,7 +3149,7 @@ dependencies = [ "pin-project", "reqwest", "rlp", - "secp256k1", + "secp256k1 0.27.0", "serde", "serde_json", "soketto", diff --git a/core/src/vm/error.rs b/core/src/vm/error.rs index 816beb57..427aa781 100644 --- a/core/src/vm/error.rs +++ b/core/src/vm/error.rs @@ -28,4 +28,13 @@ pub enum ProcessorError { #[error("Tload flag is invalid: {0}")] TloadFlagInvalid(u64), + + #[error("Pubkey is invalid: {0}")] + PubKeyInvalid(String), + + #[error("Signature is invalid: {0}")] + SignatureInvalid(String), + + #[error("Message is invalid: {0}")] + MessageInvalid(String), } diff --git a/executor/Cargo.toml b/executor/Cargo.toml index 6c2025c8..80caf5ea 100644 --- a/executor/Cargo.toml +++ b/executor/Cargo.toml @@ -26,5 +26,7 @@ rand = "0.8" bincode = "1" byteorder = "1.3" tokio = { version = "1", features = ["full"] } +secp256k1 = { version = "0.28.1", default-features = false, features = ["hashes-std", "std", "recovery"] } +num = "0.4.1" [dev-dependencies] diff --git a/executor/src/decode.rs b/executor/src/decode.rs index bca424b7..4b31e155 100644 --- a/executor/src/decode.rs +++ b/executor/src/decode.rs @@ -75,12 +75,7 @@ pub fn decode_raw_instruction( instruction += ®2_name; } } - Opcode::CJMP - | Opcode::TSTORE - | Opcode::SCCALL - | Opcode::SLOAD - | Opcode::SSTORE - | Opcode::SIGCHECK => { + Opcode::CJMP | Opcode::TSTORE | Opcode::SCCALL | Opcode::SLOAD | Opcode::SSTORE => { instruction += &op_code.to_string(); instruction += " "; let reg1_name = format!("r{}", reg1); @@ -95,7 +90,7 @@ pub fn decode_raw_instruction( instruction += ®2_name; } } - Opcode::MOV | Opcode::NOT => { + Opcode::MOV | Opcode::NOT | Opcode::SIGCHECK => { instruction += &op_code.to_string(); instruction += " "; let reg0_name = format!("r{}", reg0); diff --git a/executor/src/ecdsa.rs b/executor/src/ecdsa.rs new file mode 100644 index 00000000..5f34e659 --- /dev/null +++ b/executor/src/ecdsa.rs @@ -0,0 +1,38 @@ +use core::types::merkle_tree::{tree_key_to_u8_arr, u8_arr_to_tree_key}; +use core::types::merkle_tree::{TreeKey, TreeValue}; +use core::vm::error::ProcessorError; +use num::{BigUint, Num}; +use secp256k1::{ecdsa, Message, PublicKey, Secp256k1}; +pub fn ecdsa_verify( + x: TreeValue, + y: TreeValue, + r: TreeValue, + s: TreeValue, + msg: TreeValue, +) -> Result { + let secp = Secp256k1::new(); + + let x_arr = tree_key_to_u8_arr(&x); + let y_arr = tree_key_to_u8_arr(&y); + + let mut pub_key_bytes = [0u8; 65]; + pub_key_bytes[0] = 4; + pub_key_bytes[1..33].copy_from_slice(&x_arr); + pub_key_bytes[33..].copy_from_slice(&y_arr); + let pubkey = PublicKey::from_slice(&pub_key_bytes) + .map_err(|e| ProcessorError::PubKeyInvalid(e.to_string()))?; + + let mut signature_bytes = [0u8; 64]; + let r_arr = tree_key_to_u8_arr(&r); + let s_arr = tree_key_to_u8_arr(&s); + + signature_bytes[..32].copy_from_slice(&r_arr); + signature_bytes[32..].copy_from_slice(&s_arr); + let sig = ecdsa::Signature::from_compact(&signature_bytes) + .map_err(|e| ProcessorError::SignatureInvalid(e.to_string()))?; + + let msg_arr = tree_key_to_u8_arr(&msg); + let message = + Message::from_slice(&msg_arr).map_err(|e| ProcessorError::MessageInvalid(e.to_string()))?; + Ok(secp.verify_ecdsa(&message, &sig, &pubkey).is_ok()) +} diff --git a/executor/src/lib.rs b/executor/src/lib.rs index b084740d..bc2be6ea 100644 --- a/executor/src/lib.rs +++ b/executor/src/lib.rs @@ -39,6 +39,7 @@ use plonky2::field::types::{Field, PrimeField64}; use regex::Regex; use std::collections::{BTreeMap, HashMap}; +use crate::ecdsa::ecdsa_verify; use crate::load_tx::{init_ctx_addr_info, load_ctx_addr_info}; use crate::tape::TapeTree; use crate::trace::{gen_memory_table, gen_tape_table}; @@ -51,6 +52,7 @@ use std::time::Instant; mod decode; +mod ecdsa; pub mod load_tx; pub mod storage; mod tape; @@ -2020,7 +2022,10 @@ impl Process { memory_op!(self, sig_s_addr + i, data, Opcode::SIGCHECK); sig_s[i as usize] = data; } - + self.registers[dst_index] = GoldilocksField::from_canonical_u8(ecdsa_verify( + pk_x, pk_y, sig_r, sig_s, msg, + )? + as u8); self.register_selector.dst = self.registers[dst_index]; } _ => panic!("not match opcode:{}", opcode), diff --git a/executor/src/tests.rs b/executor/src/tests.rs index 8bb5b92b..0a820242 100644 --- a/executor/src/tests.rs +++ b/executor/src/tests.rs @@ -15,6 +15,7 @@ use core::types::merkle_tree::tree_key_default; use core::types::merkle_tree::{decode_addr, encode_addr}; use core::vm::transaction::init_tx_context_mock; use log::{debug, LevelFilter}; +use num::{BigInt, BigUint, Num}; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::field::types::Field; use std::collections::HashMap; @@ -468,7 +469,6 @@ fn ecdsa_test() { ); } - #[test] fn gen_storage_table_test() { let mut program: Program = Program::default();