From 2ace3df94be37926b8d6e01ef6b9f32bfd05e219 Mon Sep 17 00:00:00 2001 From: joii2020 Date: Thu, 12 Oct 2023 11:03:32 +0800 Subject: [PATCH 1/5] Support EOS --- README.md | 2 +- c/auth.c | 42 +++++---- 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 + 8 files changed, 207 insertions(+), 87 deletions(-) create mode 100644 tools/ckb-auth-cli/src/eos.rs diff --git a/README.md b/README.md index 9592300..9fceb15 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/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(); From cf5c2c6b1e66cb64a22ef43725ecd896f6306f2b Mon Sep 17 00:00:00 2001 From: joii2020 Date: Thu, 12 Oct 2023 11:03:59 +0800 Subject: [PATCH 2/5] Add eos document --- docs/eos.md | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 docs/eos.md diff --git a/docs/eos.md b/docs/eos.md new file mode 100644 index 0000000..736e0c0 --- /dev/null +++ b/docs/eos.md @@ -0,0 +1,133 @@ +# [EOS](../README.md) +Here use the EOS official tool `cleos` control testing tool. + +In this context, the EOS official tool `cleos` is used alongside the ckb-auth for comparison. + +## Quick Start + +### Install eos +Recommend using precompiled binary files. You can find the official tutorial [here](https://developers.eos.io/manuals/eos/latest/install/install-prebuilt-binaries). + +Please note: +- Support is only available for x86 CPUs. +- It's advisable to use the officially recommended systems. +- In this document, only the `cleos`` binary will be used. + + +### Create Key Pairs + +`cleos` can directly generate a key pair for signing without the need to create a account, unlike other tools. (It also provides account management, but generating such a key pair within the account.) + +```bash +cleos create key --to-console +``` + +Output: +```text +Private key: 5K97VWAvvY7BGqojUwTkZ279EDfCXzae9DoArmw1DCcDHXwqpgp +Public key: EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU +``` + +### Sign + +When signing with `cleos`, three parameters are used: private key, chain-id and transaction. + +* Chain-id is a 32-byte binary data that can be obtained from `Nodeos` (`nodeos` is the core service daemon that runs on every EOSIO node) or entered manually. When entered manually, if it's too long, only the beginning is used, and if it's too short, it will fill with 0. +* Transaction is in JSON format and contains the necessary information for the transaction. cleos allows the use of `{}` (an empty JSON) as a parameter. In this context, the `context_free_data` field is employed to store the CKB sign message, enabling it to participate in the signature. Important to note: `cleos` only supports the use of double quotation marks (") when parsing JSON. Single quotation marks (') should not be used. + +```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" + ] +} +``` + +After successful execution, it will output a JSON data structure in which the `signatures` are stored in the signatures field. + +### Verify + +Begin by verify the generated signature using `cleos validate signatures`. (Based on the previous data, some unused data has been removed) + +``` +cleos validate signatures \ + -c 00112233445566778899aabbccddeeff00000000000000000000000000000000 \ + "{ \"signatures\": \ + [ \"SIG_K1_KVot8AfLZKPiuwBZKxgco4pKCCfedjtrzyJij6iTmNfkq7Pw4HgizKNBCaXCMs8TNWFUg92g653LEW5GJyS1YFJw7Ciqns\" ], \ + \"context_free_data\": \ + [ \"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff\" ] }" +``` + +Output: +```text +[ + "EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU" +] +``` +This command will only output the public key of the signature. Here, need to manually compare it to the one generated earlier. + +Finally, verify the signature using `ckb-auth-cli`. + +```shell +ckb-auth-cli eos verify \ + --pubkey EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU \ + --signature SIG_K1_KVot8AfLZKPiuwBZKxgco4pKCCfedjtrzyJij6iTmNfkq7Pw4HgizKNBCaXCMs8TNWFUg92g653LEW5GJyS1YFJw7Ciqns \ + --chain_id 00112233445566778899aabbccddeeff00000000000000000000000000000000 \ + --message 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +``` + +If successful, output `Success` + +## Details of EOS + +### Public key + +In EOS transactions, public keys are directly used instead of an address. Therefore, there is no need for conversion here. The public key in EOS is a text string. +e.g. `EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU` + +It consists of three parts: +* Prefix EOS. It's possible for this to be other text, like PUB_K1([For details, please refer to the code](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 after the prefix can be decoded using the default Base58 decoding. After decoding, Aafter decoding, it is a 37-byte binary data. The first 33 bytes in this data represent the actual public key, and the last 4 bytes are for checksum (used to verify the integrity of the public key). +* When verifying, the public key is hashed using `Ripemd160`, and the first 4 bytes of the resulting data are compared for validation. + +Because EOS doesn't have address, and CKB-auth's `pubkeyhash` can only store 20 bytes, a similar signing method to CKB will be applied to the public key here. It will be hashed using Blake2b-256, and the first 20 bytes of the resulting hash will serve as the "public key hash" for CKB-auth. + + +### Sign and Verify + +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. [Official documentation](https://developers.eos.io/welcome/v2.1/protocol-guides/transactions_protocol). + + +The chain ID identifies the actual 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 runs 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 that the correct chain ID is used for the specific blockchain you are interacting with. +In `cleos`, if not detected `chain-id`, it will be get through `nodeos`. (`nodeos` is the core service daemon that runs on every EOSIO node, [Documentation](https://developers.eos.io/manuals/eos/latest/nodeos/index)). + +The information provided 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 worth noting that in practice, A fixed value can be used here, such as filling it with `0` or using the mainnet's ID. +[Details of hash](https://github.com/EOSIO/eos/blob/master/libraries/chain/transaction.cpp#L47) + +After the signing process is completed, a json will be returned, from which the signature data can be obtained: +``` +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 are the actual signature data, followed by a 4-character checksum. From 93f4fef287cba6e6f8b872c38d8b0b6caabf9c65 Mon Sep 17 00:00:00 2001 From: joii2020 Date: Thu, 12 Oct 2023 14:07:03 +0800 Subject: [PATCH 3/5] Optimize CI process --- .github/workflows/clang.yml | 2 ++ .github/workflows/rust.yml | 2 ++ 2 files changed, 4 insertions(+) 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 From b279170ecd5da6958dd36bf221d78987cc753c06 Mon Sep 17 00:00:00 2001 From: joii2020 Date: Mon, 16 Oct 2023 15:15:24 +0800 Subject: [PATCH 4/5] Update eos linke in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fceb15..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](./docs/EOS.md) +* [EOS](./docs/eos.md) * Tron * Dogecoin * CKB From da9d8d0dae0c84313fb6b05c652197077808b24f Mon Sep 17 00:00:00 2001 From: joii2020 Date: Mon, 23 Oct 2023 15:23:13 +0800 Subject: [PATCH 5/5] Rearrange some descriptions of eos.md --- docs/eos.md | 81 ++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/docs/eos.md b/docs/eos.md index 736e0c0..133fc9f 100644 --- a/docs/eos.md +++ b/docs/eos.md @@ -1,39 +1,34 @@ # [EOS](../README.md) -Here use the EOS official tool `cleos` control testing tool. -In this context, the EOS official tool `cleos` is used alongside the ckb-auth for comparison. +In this guide, we will explore how to test `ckb-auth` using the official EOS tool: `cleos`. ## Quick Start -### Install eos -Recommend using precompiled binary files. You can find the official tutorial [here](https://developers.eos.io/manuals/eos/latest/install/install-prebuilt-binaries). +### Installing EOS -Please note: -- Support is only available for x86 CPUs. -- It's advisable to use the officially recommended systems. -- In this document, only the `cleos`` binary will be used. +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. -### Create Key Pairs +### Creating Key Pairs -`cleos` can directly generate a key pair for signing without the need to create a account, unlike other tools. (It also provides account management, but generating such a key pair within the account.) +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 ``` -Output: +This command will produce output like this: ```text Private key: 5K97VWAvvY7BGqojUwTkZ279EDfCXzae9DoArmw1DCcDHXwqpgp Public key: EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU ``` -### Sign +### Signing Transactions -When signing with `cleos`, three parameters are used: private key, chain-id and transaction. - -* Chain-id is a 32-byte binary data that can be obtained from `Nodeos` (`nodeos` is the core service daemon that runs on every EOSIO node) or entered manually. When entered manually, if it's too long, only the beginning is used, and if it's too short, it will fill with 0. -* Transaction is in JSON format and contains the necessary information for the transaction. cleos allows the use of `{}` (an empty JSON) as a parameter. In this context, the `context_free_data` field is employed to store the CKB sign message, enabling it to participate in the signature. Important to note: `cleos` only supports the use of double quotation marks (") when parsing JSON. Single quotation marks (') should not be used. +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 \ @@ -62,13 +57,17 @@ Output: } ``` -After successful execution, it will output a JSON data structure in which the `signatures` are stored in the signatures field. +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.) -### Verify +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. -Begin by verify the generated signature using `cleos validate signatures`. (Based on the previous data, some unused data has been removed) +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\": \ @@ -83,9 +82,10 @@ Output: "EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU" ] ``` -This command will only output the public key of the signature. Here, need to manually compare it to the one generated earlier. -Finally, verify the signature using `ckb-auth-cli`. +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 \ @@ -95,39 +95,36 @@ ckb-auth-cli eos verify \ --message 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff ``` -If successful, output `Success` +If successful, it will return "Success." + +## EOS Transaction Details + +### Public Key -## Details of EOS +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: -### Public key +- 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. -In EOS transactions, public keys are directly used instead of an address. Therefore, there is no need for conversion here. The public key in EOS is a text string. -e.g. `EOS8Mizk2hTcnU8t3hpYErmNuWmptstbsmr3gGUeQY9swEw2AxeyU` +- 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. -It consists of three parts: -* Prefix EOS. It's possible for this to be other text, like PUB_K1([For details, please refer to the code](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 after the prefix can be decoded using the default Base58 decoding. After decoding, Aafter decoding, it is a 37-byte binary data. The first 33 bytes in this data represent the actual public key, and the last 4 bytes are for checksum (used to verify the integrity of the public key). -* When verifying, the public key is hashed using `Ripemd160`, and the first 4 bytes of the resulting data are compared for validation. +- 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 address, and CKB-auth's `pubkeyhash` can only store 20 bytes, a similar signing method to CKB will be applied to the public key here. It will be hashed using Blake2b-256, and the first 20 bytes of the resulting hash will serve as the "public key hash" for CKB-auth. +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 -### Sign and Verify +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 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. [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 chain ID identifies the actual 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 runs 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 that the correct chain ID is used for the specific blockchain you are interacting with. -In `cleos`, if not detected `chain-id`, it will be get through `nodeos`. (`nodeos` is the core service daemon that runs on every EOSIO node, [Documentation](https://developers.eos.io/manuals/eos/latest/nodeos/index)). +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). -The information provided 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 worth noting that in practice, A fixed value can be used here, such as filling it with `0` or using the mainnet's ID. -[Details of hash](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: -After the signing process is completed, a json will be returned, from which the signature data can be obtained: ``` 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 are the actual signature data, followed by a 4-character checksum. +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