diff --git a/.gitignore b/.gitignore index 5e04a34..6ed2593 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ target/* .vscode/* */build/* -Cargo.lock \ No newline at end of file +Cargo.lock +/ckb-miscellaneous-scripts +.history \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 556adaa..697e2fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,15 +8,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" -[[package]] -name = "blake2b-rs" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e35e362830ef90ecea16f09b21b75d22d33a8562a679c74ab4f4fa49b4fcb87" -dependencies = [ - "cc", -] - [[package]] name = "blake2b-rs" version = "0.2.0" @@ -48,12 +39,6 @@ version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -62,9 +47,10 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ckb-lib-rsa" -version = "0.1.0" +version = "0.3.0" dependencies = [ - "blake2b-rs 0.1.5", + "blake2b-rs", + "cfg-if", "ckb-std", "email-rs", "sha2", @@ -74,38 +60,41 @@ dependencies = [ name = "ckb-lib-secp256k1" version = "0.1.0" dependencies = [ - "blake2b-rs 0.1.5", + "blake2b-rs", + "cfg-if", "ckb-std", ] [[package]] name = "ckb-lib-smt" -version = "0.1.0" +version = "0.3.0" dependencies = [ - "blake2b-rs 0.2.0", + "blake2b-rs", "cc", + "cfg-if", "ckb-std", ] [[package]] name = "ckb-standalone-types" -version = "0.0.1-pre.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2cdbdf65ee5b1da71504f5a03d6984bce77d0b4b46daff63f4ba4a3b0eef08" +checksum = "22d7cbbdab96e6b809a102cf88bfec28795a0a3c06bfdea4abe4de89777801cd" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "molecule", ] [[package]] name = "ckb-std" -version = "0.7.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5247e68ff32c17714105e2460db6113fb99efde8c830bbdd99f8bf715100dd64" +checksum = "e5761f11372e794d77b8e8a8059b22c5d6ccef907588dd5302a669f056ecce6b" dependencies = [ "buddy-alloc", "cc", "ckb-standalone-types", + "cstr_core", ] [[package]] @@ -117,6 +106,16 @@ dependencies = [ "libc", ] +[[package]] +name = "cstr_core" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ba9efe9e1e736671d5a03f006afc4e7e3f32503e2077e0bcaf519c0c8c1d3" +dependencies = [ + "cty", + "memchr", +] + [[package]] name = "cty" version = "0.2.1" @@ -135,7 +134,7 @@ dependencies = [ [[package]] name = "email-rs" version = "0.1.0" -source = "git+https://github.com/sking789/email-rs.git#d2ae69b07b81ab2fd248272c7e4e5612efa26343" +source = "git+https://github.com/sking789/email-rs.git?branch=multi-dkim-header#ca13ab53db47f5c3e8e0aaa56a0e647d1adc6e96" dependencies = [ "base64", ] @@ -152,17 +151,23 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.101" +version = "0.2.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" + +[[package]] +name = "memchr" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "molecule" -version = "0.6.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3067ceba3d7f5dcc7427cfc584fc506e756f1161151032fec840455f5a3c2fd5" +checksum = "be5f63176422224eadd975789462a96cedaf339cd1009ef92fbdfaad39d35f5f" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -178,7 +183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", "opaque-debug", diff --git a/Cargo.toml b/Cargo.toml index a724911..d2f90c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,6 @@ [workspace] -members = ["ckb-lib-rsa","ckb-lib-secp256k1","ckb-lib-smt"] \ No newline at end of file +members = [ + "ckb-lib-rsa", + "ckb-lib-secp256k1", + "ckb-lib-smt", + ] \ No newline at end of file diff --git a/README.md b/README.md index 8e120fb..373690f 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,17 @@ git clone https://github.com/nervosnetwork/ckb-miscellaneous-scripts cd ckb-miscellaneous-scripts +git checkout -b static-lib + +git pull origin static-lib + make all-via-docker -mv ./c/build/ckb_smt ./ckb-lib-smt/lib/ +make static-via-docker + +cp ./ckb-miscellaneous-scripts/build/librsa_secp256k1.a ./ckb-lib-smt/lib/ -mv ./ckb-miscellaneous-scripts/build/secp256k1_blake2b_sighash_all_dual ./ckb-lib-secp256k1/lib +cp ./ckb-miscellaneous-scripts/build/librsa_secp256k1.a ./ckb-lib-secp256k1/lib -mv ./ckb-miscellaneous-scripts/build/rsa_sighash_all ./ckb-lib-rsa/lib +cp ./ckb-miscellaneous-scripts/build/librsa_secp256k1.a ./ckb-lib-rsa/lib +``` diff --git a/ckb-lib-rsa/Cargo.toml b/ckb-lib-rsa/Cargo.toml index b517c62..6f11635 100644 --- a/ckb-lib-rsa/Cargo.toml +++ b/ckb-lib-rsa/Cargo.toml @@ -2,19 +2,20 @@ authors = ["johnz "] edition = "2018" name = "ckb-lib-rsa" -version = "0.1.0" +version = "0.3.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ckb-std = {version = "0.7",optional = true} -email-rs = {git = "https://github.com/sking789/email-rs.git"} +cfg-if = "1.0" +ckb-std = {version = "0.9",optional = true} +email-rs = {git = "https://github.com/sking789/email-rs.git", branch = "multi-dkim-header"} sha2 = {version = "0.9.2", default-features = false} [build-dependencies] -blake2b-rs = "0.1.5" +cfg-if = "1.0" +blake2b-rs = "0.2" [features] -no_std = ["ckb-std"] -c_file = [] -default = ["no_std"] \ No newline at end of file +static_lib = ["ckb-std"] +dynamic_lib = ["ckb-std"] \ No newline at end of file diff --git a/ckb-lib-rsa/build.rs b/ckb-lib-rsa/build.rs index 0d64b50..cd8226d 100644 --- a/ckb-lib-rsa/build.rs +++ b/ckb-lib-rsa/build.rs @@ -1,57 +1,76 @@ -pub use blake2b_rs::{Blake2b, Blake2bBuilder}; +use std::path::Path; -use std::{ - fs::File, - io::{BufWriter, Read, Write}, - path::Path, -}; +cfg_if::cfg_if! { + if #[cfg(feature="static_lib")] { + fn build_fn() { + let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + println!( + "cargo:rustc-link-search=native={}", + Path::new(&dir).join("lib").display() + ); + println!("cargo:rustc-link-lib=static=rsa_secp256k1"); + } + } else { + use std::{ + fs::File, + io::{BufWriter, Read, Write}, + }; -const BUF_SIZE: usize = 8 * 1024; -const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; + const BUF_SIZE: usize = 8 * 1024; -fn main() { - let paths = [( - "RSA", - // Path::new("../ckb-production-scripts/build/validate_signature_rsa"), - Path::new("./lib/rsa_sighash_all"), - )]; - - if paths.iter().find(|(_, path)| !path.exists()).is_some() { - return; - } + fn build_fn() { + let paths = [( + "RSA", + // Path::new("../ckb-production-scripts/build/validate_signature_rsa"), + Path::new("./lib/rsa_sighash_all"), + )]; - let out_path = Path::new("src").join("code_hashes.rs"); - let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); - - paths.iter().for_each(|(name, path)| { - let mut buf = [0u8; BUF_SIZE]; - - // build hash - let mut blake2b = new_blake2b(); - let mut fd = File::open(path).expect("open file"); - loop { - let read_bytes = fd.read(&mut buf).expect("read file"); - if read_bytes > 0 { - blake2b.update(&buf[..read_bytes]); - } else { - break; + if paths.iter().find(|(_, path)| !path.exists()).is_some() { + return; } + + let out_path = Path::new("src").join("code_hashes.rs"); + let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); + + paths.iter().for_each(|(name, path)| { + let mut buf = [0u8; BUF_SIZE]; + + // build hash + let mut blake2b = new_blake2b(); + let mut fd = File::open(path).expect("open file"); + loop { + let read_bytes = fd.read(&mut buf).expect("read file"); + if read_bytes > 0 { + blake2b.update(&buf[..read_bytes]); + } else { + break; + } + } + + let mut hash = [0u8; 32]; + blake2b.finalize(&mut hash); + + write!( + &mut out_file, + "pub const CODE_HASH_{:}: [u8; 32] = {:?};\n", + name, hash + ) + .expect("write to code_hashes.rs"); + }); } - let mut hash = [0u8; 32]; - blake2b.finalize(&mut hash); + pub use blake2b_rs::{Blake2b, Blake2bBuilder}; + + const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; - write!( - &mut out_file, - "pub const CODE_HASH_{:}: [u8; 32] = {:?};\n", - name, hash - ) - .expect("write to code_hashes.rs"); - }); + pub fn new_blake2b() -> Blake2b { + Blake2bBuilder::new(32) + .personal(CKB_HASH_PERSONALIZATION) + .build() + } + } } -pub fn new_blake2b() -> Blake2b { - Blake2bBuilder::new(32) - .personal(CKB_HASH_PERSONALIZATION) - .build() +fn main() { + build_fn() } diff --git a/ckb-lib-rsa/lib/librsa_secp256k1.a b/ckb-lib-rsa/lib/librsa_secp256k1.a new file mode 100644 index 0000000..ba06687 Binary files /dev/null and b/ckb-lib-rsa/lib/librsa_secp256k1.a differ diff --git a/ckb-lib-rsa/src/lib.rs b/ckb-lib-rsa/src/lib.rs index 422e35c..5c33fee 100644 --- a/ckb-lib-rsa/src/lib.rs +++ b/ckb-lib-rsa/src/lib.rs @@ -6,25 +6,26 @@ * @Description: In User Settings Edit * @FilePath: /ckb-lib-c-script/ckb-lib-rsa/src/lib.rs */ -#![no_std] -#[cfg(all(feature = "c_file", feature = "no_std"))] -compile_error!("feature \"no_std\" and feature \"c_file\" cannot be enabled at the same time"); - -#[cfg(feature = "no_std")] -extern crate alloc; - -mod code_hashes; -#[cfg(feature = "no_std")] -mod librsa; - -pub use code_hashes::CODE_HASH_RSA; -#[cfg(feature = "no_std")] -pub use librsa::*; -pub mod email_rs{ +pub mod email_rs { pub use email_rs::*; } -#[cfg(feature = "c_file")] -pub fn get_librsa_bin() -> &'static [u8] { - include_bytes!("../lib/rsa_sighash_all") +cfg_if::cfg_if! { + if #[cfg(feature = "static_lib" )] { + extern crate alloc; + + mod librsa_static; + pub use librsa_static::*; + } else if #[cfg(feature = "dynamic_lib")] { + extern crate alloc; + + mod code_hashes; + pub use code_hashes::CODE_HASH_RSA; + mod librsa_dynamic; + pub use librsa_dynamic::*; + } else { + pub fn get_librsa_bin() -> &'static [u8] { + include_bytes!("../lib/rsa_sighash_all") + } + } } diff --git a/ckb-lib-rsa/src/librsa.rs b/ckb-lib-rsa/src/librsa_dynamic.rs similarity index 84% rename from ckb-lib-rsa/src/librsa.rs rename to ckb-lib-rsa/src/librsa_dynamic.rs index 09d381c..b45daed 100644 --- a/ckb-lib-rsa/src/librsa.rs +++ b/ckb-lib-rsa/src/librsa_dynamic.rs @@ -4,10 +4,7 @@ use crate::alloc::{ vec::*, }; use crate::code_hashes::CODE_HASH_RSA; -use ckb_std::{ - debug, - dynamic_loading_c_impl::{CKBDLContext, Symbol}, -}; +use ckb_std::dynamic_loading_c_impl::{CKBDLContext, Symbol}; use email_rs::Email; const CKB_VERIFY_RSA: u8 = 1; @@ -119,19 +116,28 @@ impl LibRSA { } pub fn verify_dkim_signature(&self, email: &Email, e: u32, n: Vec) -> Result<(), i32> { - let dkim_msg = email.get_dkim_message(); - let dkim_header = &email.dkim_header.as_ref().unwrap(); - - let sig = &dkim_header.signature; - let rsa_info = LibRSA::get_rsa_info(&n, e, &sig).map_err(|_err| 8)?; - - let prefilled_data = self.load_prefilled_data().unwrap(); - let _pub_key_hash = self - .validate_signature(&prefilled_data, rsa_info.as_ref(), &dkim_msg.as_bytes()) - .map_err(|_err| { - debug!("dkim verify error: {}", _err); - 1 - })?; + if email + .get_dkim_message() + .into_iter() + .zip(email.dkim_headers.iter()) + .find(|(dkim_msg, dkim_header)| { + let handle = || { + let sig = &dkim_header.signature; + let rsa_info = LibRSA::get_rsa_info(&n, e, &sig)?; + + let prefilled_data = self.load_prefilled_data().unwrap(); + self.validate_signature( + &prefilled_data, + rsa_info.as_ref(), + &dkim_msg.as_bytes(), + ) + }; + handle().is_ok() + }) + .is_none() + { + return Err(1); + } Ok(()) } diff --git a/ckb-lib-rsa/src/librsa_static.rs b/ckb-lib-rsa/src/librsa_static.rs new file mode 100644 index 0000000..b95eb76 --- /dev/null +++ b/ckb-lib-rsa/src/librsa_static.rs @@ -0,0 +1,130 @@ +use core::ptr::null; + +use crate::alloc::vec::*; +use ckb_std::dynamic_loading_c_impl::CKBDLContext; +use email_rs::Email; + +const CKB_VERIFY_RSA: u32 = 1; + +pub struct PrefilledData; +pub struct PubkeyHash([u8; 20]); + +impl PubkeyHash { + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} + +impl Default for PubkeyHash { + fn default() -> Self { + let inner = [0u8; 20]; + PubkeyHash(inner) + } +} + +impl Into<[u8; 20]> for PubkeyHash { + fn into(self) -> [u8; 20] { + self.0 + } +} + +extern "C" { + // fn load_prefilled_data(data: *mut u8, len: *mut u64) -> i32; + fn validate_signature_rsa( + prefilled_data: *const u8, + signature_buffer: *const u8, + signature_size: u64, + msg_buf: *const u8, + msg_size: u64, + output: *mut u8, + output_len: *mut u64, + ) -> isize; +} + +pub struct LibRSA; + +impl LibRSA { + pub fn load(_context: &mut CKBDLContext) -> Self { + LibRSA + } + + pub fn load_prefilled_data(&self) -> Result { + Ok(PrefilledData) + } + + pub fn validate_signature( + &self, + _prefilled_data: &PrefilledData, + signature: &[u8], + message: &[u8], + ) -> Result { + let mut pubkeyhash = PubkeyHash::default(); + let mut len: u64 = pubkeyhash.0.len() as u64; + + let error_code = unsafe { + validate_signature_rsa( + null(), + signature.as_ptr(), + signature.len() as u64, + message.as_ptr(), + message.len() as u64, + pubkeyhash.0.as_mut_ptr(), + &mut len as *mut u64, + ) + }; + + if error_code != 0 { + return Err(error_code as i32); + } + debug_assert_eq!(pubkeyhash.0.len() as u64, len); + Ok(pubkeyhash) + } + + pub fn verify_dkim_signature(&self, email: &Email, e: u32, n: Vec) -> Result<(), i32> { + if email + .get_dkim_message() + .into_iter() + .zip(email.dkim_headers.iter()) + .find(|(dkim_msg, dkim_header)| { + let handle = || { + let sig = &dkim_header.signature; + let rsa_info = LibRSA::get_rsa_info(&n, e, &sig)?; + + let prefilled_data = self.load_prefilled_data().unwrap(); + self.validate_signature( + &prefilled_data, + rsa_info.as_ref(), + &dkim_msg.as_bytes(), + ) + }; + handle().is_ok() + }) + .is_none() + { + return Err(1); + } + + Ok(()) + } + + pub fn get_rsa_info(n: &[u8], e: u32, sig: &[u8]) -> Result, i32> { + if n.len() != sig.len() { + return Err(8); + } + let pub_key_size: u32 = (n.len() as u32) * 8; + let rsa_info_len = pub_key_size / 4 + 12; + + let mut rsa_info = Vec::new(); + for _ in 0..rsa_info_len { + rsa_info.push(0u8); + } + + rsa_info[0..4].copy_from_slice(&CKB_VERIFY_RSA.to_le_bytes()); + rsa_info[4..8].copy_from_slice(&pub_key_size.to_le_bytes()); + rsa_info[8..12].copy_from_slice(&e.to_le_bytes()); + rsa_info[12..(12 + n.len())].copy_from_slice(&n); + rsa_info[(12 + n.len())..(12 + n.len() * 2)].copy_from_slice(sig); + + Ok(rsa_info) + } +} diff --git a/ckb-lib-secp256k1/Cargo.toml b/ckb-lib-secp256k1/Cargo.toml index b448344..e65ba18 100644 --- a/ckb-lib-secp256k1/Cargo.toml +++ b/ckb-lib-secp256k1/Cargo.toml @@ -8,12 +8,13 @@ description = "CKB secp256k1 dynamic linking library" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ckb-std = {version = "0.7.4",optional = true} +cfg-if = "1.0" +ckb-std = {version = "0.9",optional = true} [build-dependencies] -blake2b-rs = "0.1.5" +cfg-if = "1.0" +blake2b-rs = "0.2" [features] -no_std = ["ckb-std"] -c_file = [] -default = ["no_std"] \ No newline at end of file +static_lib = ["ckb-std"] +dynamic_lib = ["ckb-std"] \ No newline at end of file diff --git a/ckb-lib-secp256k1/build.rs b/ckb-lib-secp256k1/build.rs index 6167db5..c233aee 100644 --- a/ckb-lib-secp256k1/build.rs +++ b/ckb-lib-secp256k1/build.rs @@ -1,52 +1,70 @@ -pub use blake2b_rs::{Blake2b, Blake2bBuilder}; +use std::path::Path; -use std::{ - fs::File, - io::{BufWriter, Read, Write}, - path::Path, -}; +cfg_if::cfg_if! { + if #[cfg(feature="static_lib")] { + fn build_fn() { + let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + println!( + "cargo:rustc-link-search=native={}", + Path::new(&dir).join("lib").display() + ); + println!("cargo:rustc-link-lib=static=rsa_secp256k1"); + } + } else { + use std::{ + fs::File, + io::{BufWriter, Read, Write}, + }; -const BUF_SIZE: usize = 8 * 1024; -const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; + const BUF_SIZE: usize = 8 * 1024; + fn build_fn() { + let path = Path::new("./lib/secp256k1_blake2b_sighash_all_dual"); -fn main() { - let path = Path::new("./lib/secp256k1_blake2b_sighash_all_dual"); + if !path.exists() { + // do nothing if binary is not exists + return; + } - if !path.exists() { - // do nothing if binary is not exists - return; - } + let out_path = Path::new("src").join("code_hashes.rs"); + let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); - let out_path = Path::new("src").join("code_hashes.rs"); - let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); + let mut buf = [0u8; BUF_SIZE]; - let mut buf = [0u8; BUF_SIZE]; + // build hash + let mut blake2b = new_blake2b(); + let mut fd = File::open(path).expect("open file"); + loop { + let read_bytes = fd.read(&mut buf).expect("read file"); + if read_bytes > 0 { + blake2b.update(&buf[..read_bytes]); + } else { + break; + } + } - // build hash - let mut blake2b = new_blake2b(); - let mut fd = File::open(path).expect("open file"); - loop { - let read_bytes = fd.read(&mut buf).expect("read file"); - if read_bytes > 0 { - blake2b.update(&buf[..read_bytes]); - } else { - break; + let mut hash = [0u8; 32]; + blake2b.finalize(&mut hash); + + write!( + &mut out_file, + "pub const CODE_HASH_SECP256K1: [u8; 32] = {:?};\n", + hash + ) + .expect("write to code_hashes.rs"); } - } - let mut hash = [0u8; 32]; - blake2b.finalize(&mut hash); + pub use blake2b_rs::{Blake2b, Blake2bBuilder}; - write!( - &mut out_file, - "pub const CODE_HASH_SECP256K1: [u8; 32] = {:?};\n", - hash - ) - .expect("write to code_hashes.rs"); + const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; + + pub fn new_blake2b() -> Blake2b { + Blake2bBuilder::new(32) + .personal(CKB_HASH_PERSONALIZATION) + .build() + } + } } -pub fn new_blake2b() -> Blake2b { - Blake2bBuilder::new(32) - .personal(CKB_HASH_PERSONALIZATION) - .build() +fn main() { + build_fn() } diff --git a/ckb-lib-secp256k1/lib/librsa_secp256k1.a b/ckb-lib-secp256k1/lib/librsa_secp256k1.a new file mode 100644 index 0000000..ba06687 Binary files /dev/null and b/ckb-lib-secp256k1/lib/librsa_secp256k1.a differ diff --git a/ckb-lib-secp256k1/lib/secp256k1_blake2b_sighash_all_dual b/ckb-lib-secp256k1/lib/secp256k1_blake2b_sighash_all_dual index c239baf..f562d93 100755 Binary files a/ckb-lib-secp256k1/lib/secp256k1_blake2b_sighash_all_dual and b/ckb-lib-secp256k1/lib/secp256k1_blake2b_sighash_all_dual differ diff --git a/ckb-lib-secp256k1/src/code_hashes.rs b/ckb-lib-secp256k1/src/code_hashes.rs index 5cfde30..0da580d 100644 --- a/ckb-lib-secp256k1/src/code_hashes.rs +++ b/ckb-lib-secp256k1/src/code_hashes.rs @@ -1 +1 @@ -pub const CODE_HASH_SECP256K1: [u8; 32] = [160, 29, 87, 248, 84, 204, 150, 92, 216, 133, 12, 6, 105, 29, 102, 111, 147, 61, 131, 137, 214, 147, 38, 98, 115, 189, 108, 71, 117, 60, 244, 71]; +pub const CODE_HASH_SECP256K1: [u8; 32] = [229, 138, 50, 160, 6, 244, 115, 115, 102, 101, 141, 28, 48, 234, 254, 141, 185, 179, 37, 216, 121, 172, 43, 196, 212, 12, 99, 110, 125, 13, 255, 245]; diff --git a/ckb-lib-secp256k1/src/lib.rs b/ckb-lib-secp256k1/src/lib.rs index 9a6d624..681b14c 100644 --- a/ckb-lib-secp256k1/src/lib.rs +++ b/ckb-lib-secp256k1/src/lib.rs @@ -1,19 +1,21 @@ -#![no_std] -#[cfg(all(feature = "c_file", feature = "no_std"))] -compile_error!("feature \"no_std\" and feature \"std\" cannot be enabled at the same time"); -#[cfg(feature = "no_std")] -extern crate alloc; +cfg_if::cfg_if! { + if #[cfg(features = "static_lib")] { + extern crate alloc; -mod code_hashes; -#[cfg(feature = "no_std")] -mod libsecp256k1; + mod libsecp256k1_static; + pub use libsecp256k1_static::*; + } else if #[cfg(feature = "dynamic_lib")] { + extern crate alloc; + + mod code_hashes; + pub use code_hashes::CODE_HASH_SECP256K1; + mod libsecp256k1_dynamic; + pub use libsecp256k1_dynamic::*; + } else { + pub fn get_libsecp256k1_bin() -> &'static [u8] { + include_bytes!("../lib/secp256k1_blake2b_sighash_all_dual") + } + } +} -pub use code_hashes::CODE_HASH_SECP256K1; -#[cfg(feature = "no_std")] -pub use libsecp256k1::*; - -#[cfg(feature = "c_file")] -pub fn get_libsecp256k1_bin() -> &'static [u8] { - include_bytes!("../lib/secp256k1_blake2b_sighash_all_dual") -} \ No newline at end of file diff --git a/ckb-lib-secp256k1/src/libsecp256k1.rs b/ckb-lib-secp256k1/src/libsecp256k1_dynamic.rs similarity index 95% rename from ckb-lib-secp256k1/src/libsecp256k1.rs rename to ckb-lib-secp256k1/src/libsecp256k1_dynamic.rs index 4147590..e5f8f54 100644 --- a/ckb-lib-secp256k1/src/libsecp256k1.rs +++ b/ckb-lib-secp256k1/src/libsecp256k1_dynamic.rs @@ -1,5 +1,8 @@ +use crate::alloc::{ + alloc::{alloc, Layout}, + boxed::Box, +}; use crate::code_hashes::CODE_HASH_SECP256K1; -use crate::alloc::{alloc::{alloc, Layout}, boxed::Box}; use ckb_std::dynamic_loading_c_impl::{CKBDLContext, Symbol}; /// function signature of validate_secp256k1_blake2b_sighash_all @@ -25,7 +28,7 @@ const LOAD_PREFILLED_DATA: &[u8; 19] = b"load_prefilled_data"; const SECP256K1_DATA_SIZE: usize = 1048576; pub struct PrefilledData(Box<[u8; SECP256K1_DATA_SIZE]>); -pub struct Pubkey([u8; 33]); +pub struct Pubkey([u8; 65]); impl Pubkey { pub fn as_slice(&self) -> &[u8] { @@ -35,13 +38,13 @@ impl Pubkey { impl Default for Pubkey { fn default() -> Self { - let inner = [0u8; 33]; + let inner = [0u8; 65]; Pubkey(inner) } } -impl Into<[u8; 33]> for Pubkey { - fn into(self) -> [u8; 33] { +impl Into<[u8; 65]> for Pubkey { + fn into(self) -> [u8; 65] { self.0 } } diff --git a/ckb-lib-secp256k1/src/libsecp256k1_static.rs b/ckb-lib-secp256k1/src/libsecp256k1_static.rs new file mode 100644 index 0000000..585ffa1 --- /dev/null +++ b/ckb-lib-secp256k1/src/libsecp256k1_static.rs @@ -0,0 +1,103 @@ +use crate::alloc::{ + alloc::{alloc, Layout}, + boxed::Box, +}; +use ckb_std::dynamic_loading_c_impl::CKBDLContext; + +const SECP256K1_DATA_SIZE: usize = 1048576; +pub struct PrefilledData(Box<[u8; SECP256K1_DATA_SIZE]>); +pub struct Pubkey([u8; 65]); + +impl Pubkey { + pub fn as_slice(&self) -> &[u8] { + &self.0 + } +} + +impl Default for Pubkey { + fn default() -> Self { + let inner = [0u8; 65]; + Pubkey(inner) + } +} + +impl Into<[u8; 65]> for Pubkey { + fn into(self) -> [u8; 65] { + self.0 + } +} +pub struct LibSecp256k1; + +extern "C" { + fn load_prefilled_data(data: *mut u8, len: *mut u64) -> isize; + + fn validate_signature_secp256k1( + prefilled_data: *const u8, + signature_buffer: *const u8, + signature_size: u64, + msg_buf: *const u8, + msg_size: u64, + output: *mut u8, + output_len: *mut u64, + ) -> isize; + fn validate_secp256k1_blake2b_sighash_all(output_public_key_hash: *mut u8) -> isize; + +} + +impl LibSecp256k1 { + pub fn load(_context: &mut CKBDLContext) -> Self { + LibSecp256k1 + } + + pub fn validate_blake2b_sighash_all(&self, pubkey_hash: &mut [u8; 20]) -> Result<(), i32> { + let error_code = + unsafe { validate_secp256k1_blake2b_sighash_all(pubkey_hash.as_mut_ptr()) }; + if error_code != 0 { + return Err(error_code as i32); + } + Ok(()) + } + + pub fn load_prefilled_data(&self) -> Result { + let mut data = unsafe { + let layout = Layout::new::<[u8; SECP256K1_DATA_SIZE]>(); + let raw_allocation = alloc(layout) as *mut [u8; SECP256K1_DATA_SIZE]; + Box::from_raw(raw_allocation) + }; + let mut len: u64 = SECP256K1_DATA_SIZE as u64; + + let error_code = unsafe { load_prefilled_data(data.as_mut_ptr(), &mut len as *mut u64) }; + if error_code != 0 { + return Err(error_code as i32); + } + Ok(PrefilledData(data)) + } + + pub fn recover_pubkey( + &self, + prefilled_data: &PrefilledData, + signature: &[u8], + message: &[u8], + ) -> Result { + let mut pubkey = Pubkey::default(); + let mut len: u64 = pubkey.0.len() as u64; + + let error_code = unsafe { + validate_signature_secp256k1( + prefilled_data.0.as_ptr(), + signature.as_ptr(), + signature.len() as u64, + message.as_ptr(), + message.len() as u64, + pubkey.0.as_mut_ptr(), + &mut len as *mut u64, + ) + }; + + if error_code != 0 { + return Err(error_code as i32); + } + debug_assert_eq!(pubkey.0.len() as u64, len); + Ok(pubkey) + } +} diff --git a/ckb-lib-smt/Cargo.toml b/ckb-lib-smt/Cargo.toml index c29054c..eb4e823 100644 --- a/ckb-lib-smt/Cargo.toml +++ b/ckb-lib-smt/Cargo.toml @@ -1,19 +1,19 @@ [package] name = "ckb-lib-smt" -version = "0.1.0" +version = "0.3.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ckb-std = { version = "0.7.4", optional = true } - +cfg-if = "1.0" +ckb-std = { version = "0.9", optional = true } [build-dependencies] +cfg-if = "1.0" blake2b-rs = "0.2" cc = "1.0" [features] -no_std = ["ckb-std"] -c_file = [] -default = ["no_std"] \ No newline at end of file +static_lib = ["ckb-std"] +dynamic_lib = ["ckb-std"] diff --git a/ckb-lib-smt/build.rs b/ckb-lib-smt/build.rs index abb23bb..8a961b3 100644 --- a/ckb-lib-smt/build.rs +++ b/ckb-lib-smt/build.rs @@ -1,52 +1,69 @@ -pub use blake2b_rs::{Blake2b, Blake2bBuilder}; +use std::path::Path; -use std::{ - fs::File, - io::{BufWriter, Read, Write}, - path::Path, -}; +cfg_if::cfg_if! { + if #[cfg(feature="static_lib")] { + fn build_fn() { + let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + println!( + "cargo:rustc-link-search=native={}", + Path::new(&dir).join("lib").display() + ); + println!("cargo:rustc-link-lib=static=rsa_secp256k1"); + } + } else { + use std::{ + fs::File, + io::{BufWriter, Read, Write}, + }; + const BUF_SIZE: usize = 8 * 1024; -const BUF_SIZE: usize = 8 * 1024; -const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; + fn build_fn() { + let path = Path::new("./lib/ckb_smt"); -fn main() { - let path = Path::new("./lib/ckb_smt"); + if !path.exists() { + // do nothing if binary is not exists + return; + } - if !path.exists() { - // do nothing if binary is not exists - return; - } + let out_path = Path::new("src").join("code_hashes.rs"); + let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); + + let mut buf = [0u8; BUF_SIZE]; - let out_path = Path::new("src").join("code_hashes.rs"); - let mut out_file = BufWriter::new(File::create(&out_path).expect("create code_hashes.rs")); + // build hash + let mut blake2b = new_blake2b(); + let mut fd = File::open(path).expect("open file"); + loop { + let read_bytes = fd.read(&mut buf).expect("read file"); + if read_bytes > 0 { + blake2b.update(&buf[..read_bytes]); + } else { + break; + } + } - let mut buf = [0u8; BUF_SIZE]; + let mut hash = [0u8; 32]; + blake2b.finalize(&mut hash); - // build hash - let mut blake2b = new_blake2b(); - let mut fd = File::open(path).expect("open file"); - loop { - let read_bytes = fd.read(&mut buf).expect("read file"); - if read_bytes > 0 { - blake2b.update(&buf[..read_bytes]); - } else { - break; + write!( + &mut out_file, + "pub const CODE_HASH_CKB_SMT: [u8; 32] = {:?};\n", + hash + ) + .expect("write to code_hashes.rs"); } - } - let mut hash = [0u8; 32]; - blake2b.finalize(&mut hash); + pub use blake2b_rs::{Blake2b, Blake2bBuilder}; - write!( - &mut out_file, - "pub const CODE_HASH_CKB_SMT: [u8; 32] = {:?};\n", - hash - ) - .expect("write to code_hashes.rs"); + const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; + pub fn new_blake2b() -> Blake2b { + Blake2bBuilder::new(32) + .personal(CKB_HASH_PERSONALIZATION) + .build() + } + } } -pub fn new_blake2b() -> Blake2b { - Blake2bBuilder::new(32) - .personal(CKB_HASH_PERSONALIZATION) - .build() +fn main() { + build_fn() } diff --git a/ckb-lib-smt/lib/librsa_secp256k1.a b/ckb-lib-smt/lib/librsa_secp256k1.a new file mode 100644 index 0000000..ba06687 Binary files /dev/null and b/ckb-lib-smt/lib/librsa_secp256k1.a differ diff --git a/ckb-lib-smt/src/lib.rs b/ckb-lib-smt/src/lib.rs index cfa4a25..6eda097 100644 --- a/ckb-lib-smt/src/lib.rs +++ b/ckb-lib-smt/src/lib.rs @@ -1,20 +1,20 @@ +cfg_if::cfg_if! { + if #[cfg(features = "static_lib")] { + extern crate alloc; -#![no_std] -#[cfg(all(feature = "c_file", feature = "no_std"))] -compile_error!("feature \"no_std\" and feature \"c_file\" cannot be enabled at the same time"); -#[cfg(feature = "no_std")] -extern crate alloc; + mod libsmt_static; + pub use libsmt_static::*; + } else if #[cfg(features = "dynamic_lib")] { + extern crate alloc; -mod code_hashes; -#[cfg(feature = "no_std")] -mod libsmt; + mod code_hashes; + pub use code_hashes::CODE_HASH_CKB_SMT; -pub use code_hashes::CODE_HASH_CKB_SMT; -#[cfg(feature = "no_std")] -pub use libsmt::*; - - -#[cfg(feature = "c_file")] -pub fn get_libsmt_bin() -> &'static [u8] { - include_bytes!("../lib/ckb_smt") -} \ No newline at end of file + mod libsmt_dynamic; + pub use libsmt_dynamic::*; + } else { + pub fn get_libsmt_bin() -> &'static [u8] { + include_bytes!("../lib/ckb_smt") + } + } +} diff --git a/ckb-lib-smt/src/libsmt.rs b/ckb-lib-smt/src/libsmt_dynamic.rs similarity index 90% rename from ckb-lib-smt/src/libsmt.rs rename to ckb-lib-smt/src/libsmt_dynamic.rs index 225489f..71c9b43 100644 --- a/ckb-lib-smt/src/libsmt.rs +++ b/ckb-lib-smt/src/libsmt_dynamic.rs @@ -1,8 +1,5 @@ - use alloc::vec::Vec; -use ckb_std::{ - dynamic_loading_c_impl::{CKBDLContext, Symbol}, -}; +use ckb_std::dynamic_loading_c_impl::{CKBDLContext, Symbol}; const CKB_SMT_VEIRFY: &[u8; 14] = b"ckb_smt_verify"; type CKBSmtVerify = unsafe extern "C" fn( @@ -43,9 +40,7 @@ impl LibCKBSmt { let keys = keys.chunks(32).collect::>(); let values = values.chunks(32).collect::>(); - if keys.last().ok_or(-1)?.len() != 32 - || values.last().ok_or(-1)?.len() != 32 - { + if keys.last().ok_or(-1)?.len() != 32 || values.last().ok_or(-1)?.len() != 32 { return Err(-2); } diff --git a/ckb-lib-smt/src/libsmt_static.rs b/ckb-lib-smt/src/libsmt_static.rs new file mode 100644 index 0000000..aa750d5 --- /dev/null +++ b/ckb-lib-smt/src/libsmt_static.rs @@ -0,0 +1,60 @@ +use alloc::vec::Vec; +use ckb_std::dynamic_loading_c_impl::CKBDLContext; + +pub struct LibCKBSmt; + +extern "C" { + fn ckb_smt_verify( + root: *const u8, + smt_pair_len: u32, + keys: *const u8, + values: *const u8, + proof: *const u8, + proof_length: u32, + ) -> isize; +} + +impl LibCKBSmt { + pub fn load(_context: &mut CKBDLContext) -> Self { + LibCKBSmt + } + + pub fn smt_verify( + &self, + root: &[u8], + keys: &[u8], + values: &[u8], + proof: &[u8], + ) -> Result<(), i32> { + if keys.len() != values.len() || root.len() != 32 { + return Err(-1); + } + let keys = keys.chunks(32).collect::>(); + let values = values.chunks(32).collect::>(); + + if keys.last().ok_or(-1)?.len() != 32 || values.last().ok_or(-1)?.len() != 32 { + return Err(-2); + } + + let res = unsafe { + ckb_smt_verify( + root.as_ptr(), + keys.len() as u32, + keys.get(0) + .map(|x| x.as_ptr()) + .unwrap_or(keys.as_ptr() as _), + values + .get(0) + .map(|x| x.as_ptr()) + .unwrap_or(values.as_ptr() as _), + proof.as_ptr(), + proof.len() as u32, + ) + }; + if res != 0 { + Err(res as i32) + } else { + Ok(()) + } + } +} diff --git a/ckb-lib-smt/tests/test_c_file.rs b/ckb-lib-smt/tests/test_c_file.rs index d930994..ed2040d 100644 --- a/ckb-lib-smt/tests/test_c_file.rs +++ b/ckb-lib-smt/tests/test_c_file.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "c_file")] -#[cfg(not(feature = "default"))] mod test_c_file { use ckb_lib_smt::get_libsmt_bin; diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..bf867e0 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly