From 9daf7ff32cc1d429c17dced791f4458ba41c8988 Mon Sep 17 00:00:00 2001 From: joii2020 <87224197+joii2020@users.noreply.github.com> Date: Mon, 23 Oct 2023 21:19:09 -0500 Subject: [PATCH] Support EOS (#13) * Support EOS * Add eos document --- .github/workflows/clang.yml | 2 + .github/workflows/rust.yml | 2 + README.md | 2 +- c/auth.c | 42 +++++---- docs/eos.md | 130 ++++++++++++++++++++++++++++ tests/auth_rust/src/lib.rs | 60 +++++++------ tests/auth_rust/src/tests/mod.rs | 41 --------- tools/ckb-auth-cli/Cargo.lock | 1 + tools/ckb-auth-cli/Cargo.toml | 1 + tools/ckb-auth-cli/src/eos.rs | 144 +++++++++++++++++++++++++++++++ tools/ckb-auth-cli/src/main.rs | 3 + 11 files changed, 341 insertions(+), 87 deletions(-) create mode 100644 docs/eos.md create mode 100644 tools/ckb-auth-cli/src/eos.rs diff --git a/.github/workflows/clang.yml b/.github/workflows/clang.yml index 932e099..e5de7c7 100644 --- a/.github/workflows/clang.yml +++ b/.github/workflows/clang.yml @@ -42,6 +42,8 @@ jobs: run: make -f examples/auth-demo/Makefile.clang all - name: Run auth_rust tests run: cd tests/auth_rust && cargo test + - name: Clean auth_rust + run: rm -rf tests/auth_rust/target - name: Install ckb-debugger run: cd tests/auth_spawn_rust && make install - name: Run auth_spawn_rust tests diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b12ee84..f179727 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -38,6 +38,8 @@ jobs: run: make all-via-docker - name: Run auth_rust tests run: cd tests/auth_rust && bash run.sh + - name: Clean auth_rust + run: rm -rf tests/auth_rust/target - name: Install ckb-debugger run: cd tests/auth_spawn_rust && make install - name: Run auth_spawn_rust tests diff --git a/README.md b/README.md index 9592300..43b250a 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ The following blockchains are supported: * [Bitcoin](./docs/bitcoin.md) * [Ethereum](./docs/ethereum.md) -* EOS +* [EOS](./docs/eos.md) * Tron * Dogecoin * CKB diff --git a/c/auth.c b/c/auth.c index ae61b5f..d468ef9 100644 --- a/c/auth.c +++ b/c/auth.c @@ -233,6 +233,28 @@ int validate_signature_eth(void *prefilled_data, const uint8_t *sig, return ret; } +int validate_signature_eos(void *prefilled_data, const uint8_t *sig, size_t sig_len, const uint8_t *msg, size_t msg_len, + uint8_t *output, size_t *output_len) { + int err = 0; + if (*output_len < BLAKE160_SIZE) { + return SECP256K1_PUBKEY_SIZE; + } + uint8_t out_pubkey[UNCOMPRESSED_SECP256K1_PUBKEY_SIZE]; + size_t out_pubkey_size = UNCOMPRESSED_SECP256K1_PUBKEY_SIZE; + err = _recover_secp256k1_pubkey_btc(sig, sig_len, msg, msg_len, out_pubkey, &out_pubkey_size, false); + CHECK(err); + + blake2b_state ctx; + blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE); + blake2b_update(&ctx, out_pubkey, out_pubkey_size); + blake2b_final(&ctx, out_pubkey, BLAKE2B_BLOCK_SIZE); + + memcpy(output, out_pubkey, BLAKE160_SIZE); + *output_len = BLAKE160_SIZE; +exit: + return err; +} + int validate_signature_btc(void *prefilled_data, const uint8_t *sig, size_t sig_len, const uint8_t *msg, size_t msg_len, uint8_t *output, size_t *output_len) { @@ -651,24 +673,6 @@ static void split_hex_hash(const uint8_t *source, unsigned char *dest) { } } -int convert_eos_message(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, - size_t new_msg_len) { - int err = 0; - if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE) - return ERROR_INVALID_ARG; - int split_message_len = BLAKE2B_BLOCK_SIZE * 2 + 5; - unsigned char splited_message[split_message_len]; - /* split message to words length <= 12 */ - split_hex_hash(msg, splited_message); - - const mbedtls_md_info_t *md_info = - mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); - - err = md_string(md_info, msg, msg_len, new_msg); - if (err != 0) return err; - return 0; -} - #define MESSAGE_HEX_LEN 64 int convert_btc_message_variant(const uint8_t *msg, size_t msg_len, uint8_t *new_msg, size_t new_msg_len, @@ -964,7 +968,7 @@ __attribute__((visibility("default"))) int ckb_auth_validate( } else if (auth_algorithm_id == AuthAlgorithmIdEos) { CHECK2(signature_size == SECP256K1_SIGNATURE_SIZE, ERROR_INVALID_ARG); err = verify(pubkey_hash, signature, signature_size, message, - message_size, validate_signature_eth, convert_eos_message); + message_size, validate_signature_eos, convert_copy); CHECK(err); } else if (auth_algorithm_id == AuthAlgorithmIdTron) { CHECK2(signature_size == SECP256K1_SIGNATURE_SIZE, ERROR_INVALID_ARG); diff --git a/docs/eos.md b/docs/eos.md new file mode 100644 index 0000000..133fc9f --- /dev/null +++ b/docs/eos.md @@ -0,0 +1,130 @@ +# [EOS](../README.md) + +In this guide, we will explore how to test `ckb-auth` using the official EOS tool: `cleos`. + +## Quick Start + +### Installing EOS + +To get started, we recommend using precompiled binary files. You can find the official installation tutorial [here](https://developers.eos.io/manuals/eos/latest/install/install-prebuilt-binaries). Please keep in mind the following: + +- Support is available only for x86 CPUs. +- It's advisable to use the officially recommended systems. + - In this document, we will focus on using the `cleos` binary. + +### Creating Key Pairs + +One of the advantages of `cleos` is that it can directly generate a key pair for signing. Here's how you can do it: + +```bash +cleos create key --to-console +``` + +This command will produce output like this: +```text +Private key: 5K97VWAvvY7BGqojUwTkZ279EDfCXzae9DoArmw1DCcDHXwqpgp +Public key: EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU +``` + +### Signing Transactions + +When using `cleos` for signing, you'll need three parameters: a private key, a chain ID, and the transaction data. Here's an example of how to sign a transaction: + +```bash +cleos sign -k 5K97VWAvvY7BGqojUwTkZ279EDfCXzae9DoArmw1DCcDHXwqpgp \ + -c 00112233445566778899aabbccddeeff00000000000000000000000000000000 \ + "{ \"context_free_data\": [\"\00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\"] }" +``` + +Output: +```text +{ + "expiration": "1970-01-01T00:00:00", + "ref_block_num": 0, + "ref_block_prefix": 0, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [], + "transaction_extensions": [], + "signatures": [ + "SIG_K1_KVot8AfLZKPiuwBZKxgco4pKCCfedjtrzyJij6iTmNfkq7Pw4HgizKNBCaXCMs8TNWFUg92g653LEW5GJyS1YFJw7Ciqns" + ], + "context_free_data": [ + "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff" + ] +} +``` + +In the given command, `-c` (Chain ID) is a 32-byte binary data that can be acquired from `nodeos`, the core service daemon running on every EOSIO node. Alternatively, it can be entered manually. When entering it manually, if it's too long, only the beginning is used; if it's too short, it will be padded with 0s. (Please note that while cleos may perform some corrections to the chain ID, `ckb-auth-cli` does not.) + +A transaction is presented in JSON format and contains all the essential information for the transaction. `cleos` allows the use of `{}` to represent an empty JSON as a parameter. In this context, the `context_free_data` field is used to store the CKB sign message, enabling its inclusion in the signature. It's important to note that `cleos` only supports the use of double quotation marks (") when parsing JSON; single quotation marks (') should not be used. + +After successful execution, you will receive a JSON data structure with the signature stored in the "signatures" field. + +### Verifying Signatures + +You can verify the generated signature using the `cleos validate signatures` command. Here's how you can do it: + +```bash +cleos validate signatures \ + -c 00112233445566778899aabbccddeeff00000000000000000000000000000000 \ + "{ \"signatures\": \ + [ \"SIG_K1_KVot8AfLZKPiuwBZKxgco4pKCCfedjtrzyJij6iTmNfkq7Pw4HgizKNBCaXCMs8TNWFUg92g653LEW5GJyS1YFJw7Ciqns\" ], \ + \"context_free_data\": \ + [ \"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\" ] }" +``` + +Output: +```text +[ + "EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU" +] +``` + +This command will output the public key of the signature, which you can manually compare to the one generated earlier. + +To complete the verification process, you can also use `ckb-auth-cli`: + +```shell +ckb-auth-cli eos verify \ + --pubkey EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU \ + --signature SIG_K1_KVot8AfLZKPiuwBZKxgco4pKCCfedjtrzyJij6iTmNfkq7Pw4HgizKNBCaXCMs8TNWFUg92g653LEW5GJyS1YFJw7Ciqns \ + --chain_id 00112233445566778899aabbccddeeff00000000000000000000000000000000 \ + --message 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +``` + +If successful, it will return "Success." + +## EOS Transaction Details + +### Public Key + +In EOS transactions, public keys are used directly instead of an address. There's no need for conversion. An EOS public key is a text string, such as `EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU`. It consists of three parts: + +- The prefix for the public key is typically "EOS," although it's possible for this prefix to be different, such as "PUB_K1." For more details on this, please refer to the code [here](https://github.com/EOSIO/fc/blob/863dc8d371fd4da25f89cb08b13737f009a9cec7/src/crypto/public_key.cpp#L77). However, in ckb-auth-cli, only "EOS" is supported as the prefix. + +- The text following the prefix can be decoded using the default Base58 decoding method. After decoding, it results in a 37-byte binary data. The first 33 bytes of this data represent the actual public key, and the last 4 bytes are used for checksum purposes to verify the integrity of the public key. + +- During the verification process, the public key is hashed using `Ripemd160`, and the first 4 bytes of the resulting data are compared to validate its authenticity. + +Because EOS doesn't have addresses, and CKB-auth's `pubkeyhash` can only store 20 bytes, a similar signing method to CKB is applied to the public key. It's hashed using Blake2b-256, and the first 20 bytes of the resulting hash serve as the "public key hash" for CKB-auth. + +### Signing and Verification + +The provided information explains that `cleos` offers a "sign" subcommand for signing transactions. This signing process requires a private key, the chain ID, and the transaction as its inputs. You can find more details in the [official documentation](https://developers.eos.io/welcome/v2.1/protocol-guides/transactions_protocol). + +The chain ID identifies the specific EOSIO blockchain and consists of a hash of its genesis state, which depends on the blockchain’s initial configuration parameters. In `cleos`, if you do not specify the chain ID, it will be obtained from `nodeos`. `nodeos` is the core service daemon that operates on every EOSIO node and plays a central role in managing the blockchain. This automatic retrieval of the chain ID from `nodeos` simplifies the process of signing transactions by ensuring the correct chain ID is used for the specific blockchain you are interacting with. + +If the `chain-id` is not detected in `cleos`, it will be obtained through `nodeos`. (`nodeos` is the core service daemon that runs on every EOSIO node; you can refer to the [documentation](https://developers.eos.io/manuals/eos/latest/nodeos/index) for more information). + +The provided information also explains that in the transaction, the signature is based on the data in the `context_free_data` field of the JSON. This field is converted to hexadecimal in `cleos`, and the CKB sign message is placed in this field. It's important to note that, in practice, a fixed value can be used here, such as filling it with `0` or using the mainnet's ID. For more technical details, you can refer to [this source](https://github.com/EOSIO/eos/blob/master/libraries/chain/transaction.cpp#L47). + +After the signing process is completed, a JSON response is returned, from which the signature data can be extracted: + +``` +SIG_K1_KVot8AfLZKPiuwBZKxgco4pKCCfedjtrzyJij6iTmNfkq7Pw4HgizKNBCaXCMs8TNWFUg92g653LEW5GJyS1YFJw7Ciqns +``` + +This string is similar to a public key, with a prefix indicating its purpose, and "K1" signifying that it's using a K1 curve. The following data is still encoded in Base58. When decoded, the first 65 bytes represent the actual signature data, followed by a 4-character checksum. \ No newline at end of file diff --git a/tests/auth_rust/src/lib.rs b/tests/auth_rust/src/lib.rs index 405cbc9..beb06f8 100644 --- a/tests/auth_rust/src/lib.rs +++ b/tests/auth_rust/src/lib.rs @@ -110,6 +110,16 @@ pub fn calculate_sha256(buf: &[u8]) -> [u8; 32] { c.finalize().into() } +pub fn calculate_ripemd160(buf: &[u8]) -> [u8; 20] { + use mbedtls::hash::*; + let mut md = Md::new(Type::Ripemd).unwrap(); + md.update(buf).expect("hash ripemd update"); + let mut out = [0u8; 20]; + md.finish(&mut out).expect("hash ripemd finish"); + + out +} + #[derive(Clone, Copy)] pub enum AlgorithmType { Ckb = 0, @@ -892,30 +902,41 @@ impl Auth for EthereumAuth { #[derive(Clone)] pub struct EosAuth { - pub privkey: secp256k1::SecretKey, - pub pubkey: secp256k1::PublicKey, + pub privkey: Privkey, + pub compress: bool, } impl EosAuth { fn new() -> Box { - let generator: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); - let mut rng = thread_rng(); - let (privkey, pubkey) = generator.generate_keypair(&mut rng); - Box::new(EosAuth { privkey, pubkey }) + let privkey = Generator::random_privkey(); + Box::new(BitcoinAuth { + privkey, + compress: true, + }) } } impl Auth for EosAuth { fn get_pub_key_hash(&self) -> Vec { - EthereumAuth::get_eth_pub_key_hash(&self.pubkey) + let pub_key = self.privkey.pubkey().expect("pubkey"); + let pub_key_vec: Vec; + if self.compress { + pub_key_vec = pub_key.serialize(); + } else { + let mut temp: BytesMut = BytesMut::with_capacity(65); + temp.put_u8(4); + temp.put(Bytes::from(pub_key.as_bytes().to_vec())); + pub_key_vec = temp.freeze().to_vec(); + } + + ckb_hash::blake2b_256(pub_key_vec)[..20].to_vec() } fn get_algorithm_type(&self) -> u8 { AlgorithmType::Eos as u8 } fn convert_message(&self, message: &[u8; 32]) -> H256 { - let msg = calculate_sha256(message); - H256::from(msg) + H256::from(message.clone()) } fn sign(&self, msg: &H256) -> Bytes { - EthereumAuth::eth_sign(msg, &self.privkey) + BitcoinAuth::btc_sign(msg, &self.privkey, self.compress) } } @@ -966,8 +987,6 @@ impl BitcoinAuth { }) } pub fn get_btc_pub_key_hash(privkey: &Privkey, compress: bool) -> Vec { - use mbedtls::hash::{Md, Type}; - let pub_key = privkey.pubkey().expect("pubkey"); let pub_key_vec: Vec; if compress { @@ -981,8 +1000,7 @@ impl BitcoinAuth { let pub_hash = calculate_sha256(&pub_key_vec); - let mut msg = [0u8; 20]; - Md::hash(Type::Ripemd, &pub_hash, &mut msg).expect("hash ripemd"); + let msg = calculate_ripemd160(&pub_hash); msg.to_vec() } pub fn btc_convert_message(message: &[u8; 32]) -> H256 { @@ -1599,16 +1617,6 @@ impl RippleAuth { }) } - fn hash_ripemd160(data: &[u8]) -> [u8; 20] { - use mbedtls::hash::*; - let mut md = Md::new(Type::Ripemd).unwrap(); - md.update(data).expect("hash ripemd update"); - let mut out = [0u8; 20]; - md.finish(&mut out).expect("hash ripemd finish"); - - out - } - fn hash_sha256(data: &[u8]) -> [u8; 32] { use mbedtls::hash::*; let mut md = Md::new(Type::Sha256).unwrap(); @@ -1638,7 +1646,7 @@ impl RippleAuth { pub fn hex_to_address(data: &[u8]) -> String { let data = Self::hash_sha256(data); - let data: [u8; 20] = Self::hash_ripemd160(&data); + let data: [u8; 20] = calculate_ripemd160(&data); let mut data = { let mut buf = vec![0u8]; @@ -1652,7 +1660,7 @@ impl RippleAuth { } fn get_hash(data: &[u8]) -> [u8; 20] { - Self::hash_ripemd160(&Self::hash_sha256(data)) + calculate_ripemd160(&Self::hash_sha256(data)) } fn generate_tx(ckb_sign_msg: &[u8], pubkey: &[u8], sign: Option<&[u8]>) -> Vec { diff --git a/tests/auth_rust/src/tests/mod.rs b/tests/auth_rust/src/tests/mod.rs index 1660b5f..201ac50 100644 --- a/tests/auth_rust/src/tests/mod.rs +++ b/tests/auth_rust/src/tests/mod.rs @@ -355,47 +355,6 @@ fn convert_eth_error() { ); } -#[test] -fn convert_eos_error() { - #[derive(Clone)] - struct EthConverFaileAuth(EosAuth); - impl Auth for EthConverFaileAuth { - fn get_pub_key_hash(&self) -> Vec { - EthereumAuth::get_eth_pub_key_hash(&self.0.pubkey) - } - fn get_algorithm_type(&self) -> u8 { - AlgorithmType::Eos as u8 - } - fn convert_message(&self, message: &[u8; 32]) -> H256 { - use mbedtls::hash::{Md, Type::Sha256}; - let mut md = Md::new(Sha256).unwrap(); - md.update(message).expect("sha256 update data"); - md.update(&[1, 2, 3]).expect("sha256 update data"); - - let mut msg = [0u8; 32]; - md.finish(&mut msg).expect("sha256 finish"); - H256::from(msg) - } - fn sign(&self, msg: &H256) -> Bytes { - EthereumAuth::eth_sign(msg, &self.0.privkey) - } - } - - let generator: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); - let mut rng = thread_rng(); - let (privkey, pubkey) = generator.generate_keypair(&mut rng); - - let auth: Box = Box::new(EthConverFaileAuth { - 0: EosAuth { privkey, pubkey }, - }); - let config = TestConfig::new(&auth, EntryCategoryType::DynamicLinking, 1); - assert_result_error( - verify_unit(&config), - "failed conver eos", - &[AuthErrorCodeType::Mismatched as i32], - ); -} - #[test] fn convert_tron_error() { #[derive(Clone)] diff --git a/tools/ckb-auth-cli/Cargo.lock b/tools/ckb-auth-cli/Cargo.lock index 19b3c9d..dbca77b 100644 --- a/tools/ckb-auth-cli/Cargo.lock +++ b/tools/ckb-auth-cli/Cargo.lock @@ -883,6 +883,7 @@ dependencies = [ "mbedtls", "monero", "serde_json", + "sha2 0.10.7", ] [[package]] diff --git a/tools/ckb-auth-cli/Cargo.toml b/tools/ckb-auth-cli/Cargo.toml index 7beb362..fec376f 100644 --- a/tools/ckb-auth-cli/Cargo.toml +++ b/tools/ckb-auth-cli/Cargo.toml @@ -21,3 +21,4 @@ serde_json = "1.0" monero = { version = "0.18.2", features = ["serde"] } base58-monero = "1.0.0" mbedtls = "0.8.1" +sha2 = "0.10.6" diff --git a/tools/ckb-auth-cli/src/eos.rs b/tools/ckb-auth-cli/src/eos.rs new file mode 100644 index 0000000..e1098bf --- /dev/null +++ b/tools/ckb-auth-cli/src/eos.rs @@ -0,0 +1,144 @@ +use super::{BlockChain, BlockChainArgs}; +use anyhow::{anyhow, Error}; +use ckb_auth_rs::{calculate_ripemd160, AlgorithmType}; +use clap::{arg, ArgMatches, Command}; +use hex::decode; +use sha2::{Digest, Sha256}; + +pub struct EosLockArgs {} + +impl BlockChainArgs for EosLockArgs { + fn block_chain_name(&self) -> &'static str { + "eos" + } + + fn reg_parse_args(&self, cmd: Command) -> Command { + cmd + } + fn reg_generate_args(&self, cmd: Command) -> Command { + cmd + } + fn reg_verify_args(&self, cmd: Command) -> Command { + cmd.arg(arg!(-p --pubkey "The public key to verify against")) + .arg(arg!(-s --signature "The signature to verify")) + .arg( + arg!(-c --chain_id "The chain id that will be used to sign the transaction"), + ) + .arg(arg!(-m --message "message")) + } + + fn get_block_chain(&self) -> Box { + Box::new(EosLock {}) + } +} + +pub struct EosLock {} + +impl BlockChain for EosLock { + fn parse(&self, _operate_mathches: &ArgMatches) -> Result<(), Error> { + Err(anyhow!("EOS does not parse")) + } + + fn generate(&self, _operate_mathches: &ArgMatches) -> Result<(), Error> { + Err(anyhow!("EOS does not generate")) + } + + fn verify(&self, operate_mathches: &ArgMatches) -> Result<(), Error> { + let pubkey = operate_mathches + .get_one::("pubkey") + .expect("get EOS public key"); + + let signature = operate_mathches + .get_one::("signature") + .expect("get EOS signature"); + + let chain_id = decode( + operate_mathches + .get_one::("chain_id") + .expect("get chain id"), + ) + .expect("decode chain id"); + + let message = decode({ + let msg = operate_mathches + .get_one::("message") + .expect("get EOS signauthe message"); + let pos = msg.find("#"); + if pos.is_some() { + msg[0..pos.unwrap()].to_string() + } else { + msg.clone() + } + }) + .expect("decode signature message data"); + + if chain_id.len() != 32 { + return Err(anyhow!("chainid size not 32")); + } + + if message.len() != 32 { + return Err(anyhow!("message size not 32")); + } + + let mut hasher = Sha256::new(); + hasher.update(&chain_id); + hasher.update([0x00u8, 0x00u8, 0x00u8, 0x00u8]); + hasher.update([0x00u8, 0x00u8]); + hasher.update([0x00u8, 0x00u8, 0x00u8, 0x00u8]); + hasher.update([0x00u8]); + hasher.update([0x00u8]); + hasher.update([0x00u8]); + hasher.update([0x00u8]); + hasher.update([0x00u8]); + hasher.update([0x00u8]); + + let mut hasher2 = Sha256::new(); + hasher2.update([0x01u8]); + hasher2.update([0x20u8]); + hasher2.update(&message); + + hasher.update(hasher2.finalize()); + + let message = hasher.finalize(); + + if !pubkey.starts_with("EOS") { + return Err(anyhow!("EOS public key illegal")); + } + let pubkey = bs58::decode(&pubkey[3..]) + .into_vec() + .expect("Decode EOS public key by base58"); + + let pubkey_checksum = calculate_ripemd160(&pubkey[..33]); + if pubkey_checksum[..4] != pubkey[33..] { + return Err(anyhow!("check public key failed")); + } + let pubkey = pubkey[..33].to_vec(); + + if !signature.starts_with("SIG_K1_") { + return Err(anyhow!("EOS No delimiter in string")); + } + + let signature = bs58::decode(&signature[7..]) + .into_vec() + .expect("Decode EOS signature key by base58"); + + // Checksum + let sign = signature[..65].to_vec(); + let check = signature[65..].to_vec(); + let sign_checksum = { + let mut buf = sign.clone(); + buf.extend_from_slice("K1".as_bytes()); + calculate_ripemd160(&buf) + }; + if sign_checksum[..4] != check { + return Err(anyhow!("check signature failed")); + } + + let pubkey_hash = ckb_hash::blake2b_256(pubkey); + + super::auth_script::run_auth_exec(AlgorithmType::Eos, &pubkey_hash[..20], &message, &sign)?; + + println!("Success"); + Ok(()) + } +} diff --git a/tools/ckb-auth-cli/src/main.rs b/tools/ckb-auth-cli/src/main.rs index 44b8764..15c16b3 100644 --- a/tools/ckb-auth-cli/src/main.rs +++ b/tools/ckb-auth-cli/src/main.rs @@ -1,6 +1,7 @@ mod auth_script; mod bitcoin; mod cardano; +mod eos; mod ethereum; mod litecoin; mod monero; @@ -11,6 +12,7 @@ mod utils; use crate::monero::MoneroLockArgs; use bitcoin::BitcoinLockArgs; use cardano::CardanoLockArgs; +use eos::EosLockArgs; use ethereum::EthereumLockArgs; use litecoin::LitecoinLockArgs; use ripple::RippleLockArgs; @@ -86,6 +88,7 @@ fn main() -> Result<(), Error> { Box::new(RippleLockArgs {}) as Box, Box::new(BitcoinLockArgs {}) as Box, Box::new(EthereumLockArgs {}) as Box, + Box::new(EosLockArgs {}) as Box, ]; let matches = cli(block_chain_args.as_slice()).get_matches();