diff --git a/README.md b/README.md index c50ee6d..9592300 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ throughout the process. The following blockchains are supported: * [Bitcoin](./docs/bitcoin.md) -* Ethereum +* [Ethereum](./docs/ethereum.md) * EOS * Tron * Dogecoin diff --git a/docs/bitcoin.md b/docs/bitcoin.md index 00e06b1..b3e2e67 100644 --- a/docs/bitcoin.md +++ b/docs/bitcoin.md @@ -1,21 +1,21 @@ # [Bitcoin Lock](../README.md) -Here, we will be conducting comparative testing using [Bitcoin Core](https://bitcoincore.org) (Version 25.0), an official wallet. -For a more in-depth look at the specific implementations of Bitcoin, you can refer to the [source code](https://github.com/bitcoin/bitcoin). +Here, use the official wallet [Bitcoin Core](https://bitcoincore.org) (Version 25.0). ([Source code](https://github.com/bitcoin/bitcoin)) -**Please note:** that we will be using `legacy addresses`. This choice is due to the fact that the current version (25.0) of Bitcoin Core defaults to `segwit addresses`, which are not supported by `signmessage` and `verifymessage`. For further details on this matter, you can check the [Github Issues](https://github.com/bitcoin/bitcoin/issues/10542). +**Please note:** that we will be using `legacy addresses`. This choice is due to the fact that the current version (25.0) of Bitcoin Core defaults to `segwit addresses`, which are not supported by `signmessage` and `verifymessage`. For further details on this matter, For details, please see this [Github Issues](https://github.com/bitcoin/bitcoin/issues/10542). ## Quick Start ### Install Bitcoin Core -Download the binary archive from [here](https://bitcoincore.org/bin/bitcoin-core-25.0/), choose the file corresponding to your platform, and unarchive it. (Note: If you are using MacOS, we recommend downloading the `.tar.gz` file, `.dmg` file only provides GUI tools.) +Download the binary archive from [here](https://bitcoincore.org/bin/bitcoin-core-25.0/), choose the file corresponding to platform, and unarchive it. (Note: If MacOS, we recommend downloading the `.tar.gz` file, `.dmg` file only provides GUI tools.) -Once you have completed these steps, you can start the background program: `bitcoind`. The signature and verify we need to do later need to rely on this service to process. +After installation is complete, start the background program: `bitcoind`. The signature and verify we need to do later need to rely on this service to process. ```shell -bitcoind +bitcoind -chain=regtest -daemonwait ``` +(For the convenience of testing, start Bitcoin Core in Regtest mode and run it in the background, waiting until it is fully started.) Normally, we will only be using `signature` and `verify` here, without involving on-chain data. Therefore, you can consider disabling network transmission in the configuration file. Instructions on how to configure it will be provided in the following section. @@ -37,7 +37,7 @@ Output address: ### Generate Signature -First, you need to generate a 32-byte data segment as message: +To begin, generate a 32-byte data segment as the message: ```shell message=0011223344556677889900112233445500112233445566778899001122334455 ``` @@ -46,7 +46,7 @@ Next, use the `bitcoin-cli` for signing: ```shell bitcoin-cli -rpcwallet=Test signmessage 1CSbWFszmuQiPCRPsaDhhb2NuFTEZFQqih $message ``` -If the wallet has set a password before, you need to use `walletpassphrase` to unlock it first. +If the wallet requires a password, unlock it first using `walletpassphrase`. Once the signing is successful, it will output the signature result, which is encoded in base64: ``` @@ -55,7 +55,7 @@ H0v6+IkWf0WL6MDCz0K6XeTiNSChoiDIEzgJQMadJi78NoHE3roRx8QX1mnK57on5w5doBXOFBn1kwpO ### Verify -Here you can directly pass the address, signature and message to ckb-auth-cli to verify: +Pass the address, signature and message to ckb-auth-cli to verify: ```shell ckb-auth-cli bitcoin verify -a 1CSbWFszmuQiPCRPsaDhhb2NuFTEZFQqih -s H0v6+IkWf0WL6MDCz0K6XeTiNSChoiDIEzgJQMadJi78NoHE3roRx8QX1mnK57on5w5doBXOFBn1kwpOpPgVwPM= -m 0011223344556677889900112233445500112233445566778899001122334455 ``` @@ -65,7 +65,7 @@ ckb-auth-cli bitcoin verify -a 1CSbWFszmuQiPCRPsaDhhb2NuFTEZFQqih -s H0v6+IkWf0W ### Cofing Bitcoin Core -If you wish to perform testing using a GUI or disable network activity, please refer to the configuration instructions below. +For GUI testing or disabling network activity, refer to the configuration instructions below. [Help](https://jlopp.github.io/bitcoin-core-config-generator/) The configuration file for Bitcoin Core (`bitcoin.conf`) is located in different directories based on the platform: @@ -73,7 +73,7 @@ The configuration file for Bitcoin Core (`bitcoin.conf`) is located in different - Windows: `%UserProfile%\AppData\Roaming\Bitcoin\bitcoin.conf` - MacOS: `$HOME/Library/Application Support/Bitcoin/bitcoin.conf` -If you are using it for the first time, you will need to manually create these directories and files. If you want to specify a custom directory, you can also check the `bitcoind` or `bitcoin-qt` help. +First time using, need to manually create these directories and files. Disabling network activity is mainly done to reduce disk usage: @@ -97,7 +97,7 @@ To create addresses in the GUI: - Create a wallet: `File` -> `Create Wallet`. - Generate a receiving address: In the `Receive` tab, click the "Create new receiving address" button. -- After creation, you will see the `Address` in the lower part of a separate window. You can check the addresses held by the current wallet in the table below. +- After creation, the 'Address' will be visible in the lower part of a separate window. The addresses held by the current wallet can be checked in the table below. If the address starts with `bc` or `tb`, make sure to verify the correctness of the above configurations. @@ -109,11 +109,11 @@ To sign a message in the GUI: - `File` -> `Sign Message`, and enter the corresponding values for signing. -In ckb-auth, the message uses a fixed 32 bytes, but it internally converts the message to hexadecimal with a length of 64 bytes. Therefore, ensure that the message remains 32 bytes when generating it. If the data to be signed is too long, consider hashing it. For signing in Bitcoin, you can directly use this string. +In ckb-auth, the message uses a fixed 32 bytes, but it internally converts the message to hexadecimal with a length of 64 bytes. Therefore, ensure that the message remains 32 bytes when generating it. If the data to be signed is too long, consider hashing it. For signing in Bitcoin, just use string directly. Please note: When signing in Bitcoin, case sensitivity should be observed. Ckb-auth uses lowercase letters exclusively. -The returned signature data is encoded in base64, with a fixed binary length of 65 bytes. In this case, no special handling is required. After decoding, you can directly pass it to ckb-auth. +The returned signature data is encoded in base64, with a fixed binary length of 65 bytes. In this case, no special processing is required and passed directly to ckb-auth ### Verify diff --git a/docs/ethereum.md b/docs/ethereum.md new file mode 100644 index 0000000..9f7b5fc --- /dev/null +++ b/docs/ethereum.md @@ -0,0 +1,110 @@ +# [Ethereum Lock](../README.md) + +Here, we are conducting comparative testing using the official Ethereum tool [go-ethereum](https://geth.ethereum.org/) (Version 1.12.2). + +## Install +Supported installation methods: + +* Package Managers, supported on: Mac (brew), Ubuntu, FreeBSD, Arch Linux. For specific instructions, please refer to the [official documentation](https://geth.ethereum.org/docs/getting-started/installing-geth). +* [Download the standalone bundle](https://geth.ethereum.org/downloads) +* Building from [source code](https://github.com/ethereum/go-ethereum) + +Within the `geth` package, there are multiple executable files. Here, we will focus on using `geth` and `ethkey`. + +* `geth` for creating accounts and generating addresses. +* `ethkey` for signature and verification. + +Note that if using a standalone bundle or building from source, it's advisable to add the installation directory to environment variables for ease of use. + +### Build from source code +Keep in mind that compiling `geth` requires a [golang environment](https://go.dev/doc/install). + +``` +git clone https://github.com/ethereum/go-ethereum.git +cd go-ethereum +make all +``` + +As `ethkey` is required, we compile all components for convenience. The compiled results can be found in the `build/bin` directory. It's recommended to add this directory to 'PATH' environment variable for ease of use. + +## Address +First, A test account is required: +```shell +geth account new +``` + +Once created, look for this line in the output: +``` +Public address of the key: +Path of the secret key file: +``` + +Here, the account's address and private key file are displayed. To query account information again, use: `geth account list`. + +In Ethereum, the `Address` is a 20-byte fixed-length array. When used in programs (geth and ckb-auth-cli), it will handle the leading `0x`. + +If automation testing is needed, the passwordfile and keystore parameters can be employed to handle password and key storage. + +```shell +eth_password_file=`pwd`/password.txt +echo $RANDOM > $eth_password_file +eth_account_dir=`pwd`/account +rm -rf $eth_account_dir +mkdir -p $eth_account_dir +geth account new --password $eth_password_file --keystore $eth_account_dir > /dev/null 2>&1 + +eth_account_info=`geth account list --keystore $eth_account_dir 2>/dev/null` +eth_address=`echo $eth_account_info | grep -oE -m 1 '\{[a-f0-9]+\}' | sed 's/{\(.*\)}/\1/'` +eth_privkey_file=`echo $eth_account_info | grep -oE 'keystore://[^ ]+' | awk -F 'keystore:' '{print $2}'` + +echo Address: $eth_address +echo PrivateKeyFile: $eth_privkey_file +``` + +After executing the above code. The value `eth_address` is ethereum address, `eth_privkey_file` is private key file path. In subsequent operations, these two variables can be used directly. + +## Signature + +Ethereum's message is calculated using sha3: `Ethereum Signed Message:\n` + 'message' hash. While ckb-auth's message is a fixed length of 32 bytes, so here, `ethkey` supports the input of messages in both textual form and through a file (by using the `--msgfile` parameter). In this context, Ethereum's message is directly utilized as a data parameter hash, necessitating the use of the `--msgfile` to input a file. + +Here, ethkey needs to use message_file, use `ckb-auth-cli ethereum generate` to convert the message to file: +```shell +message=0011223344556677889900112233445500112233445566778899001122334455 +message_file=`pwd`/message_file.bin +ckb-auth-cli ethereum generate -m $message --msgfile $message_file +``` +(Other paths can also be used) + +After generating the message file, ethkey can be used for signing: +```shell +ethkey signmessage --msgfile $message_file --passwordfile $eth_password_file $eth_privkey_file +``` +output: +``` +Signature: 5a62aa66a32a41fb44a58e7284ca964952da485dc0fcec24dadb7402d65274d8733f9a2c34274c573d09743d04f25fdfb00ffee8d821a1422c7d3f4e97ce97e100 +``` + +If it's an automated test, obtaining the signature can also be accomplished through a script. + +```shell +eth_sign_info=`ethkey signmessage --msgfile $message_file --passwordfile $eth_password_file $eth_privkey_file` +eth_signature=`echo $eth_sign_info | awk -F 'Signature: ' '{print $2}'` +echo Signature: $eth_signature +``` + +Now, the value in `eth_signature` is signature. + +After signing, verification can be done using geth to prevent any basic errors: +```shell +ethkey verifymessage --msgfile $message_file $eth_address $eth_signature +``` + +* Here need to pay attention to the order of command parameters. + +## Verify + +This can now be verified in ckb-auth: + +```shell +ckb-auth-cli ethereum verify -a $eth_address -s $eth_signature -m $message +``` diff --git a/tools/ckb-auth-cli/rust-toolchain b/tools/ckb-auth-cli/rust-toolchain index 12816e6..68bc7ff 100644 --- a/tools/ckb-auth-cli/rust-toolchain +++ b/tools/ckb-auth-cli/rust-toolchain @@ -1 +1 @@ -1.71 +1.71.1 diff --git a/tools/ckb-auth-cli/src/ethereum.rs b/tools/ckb-auth-cli/src/ethereum.rs new file mode 100644 index 0000000..534d40e --- /dev/null +++ b/tools/ckb-auth-cli/src/ethereum.rs @@ -0,0 +1,103 @@ +use super::{BlockChain, BlockChainArgs}; +use anyhow::{anyhow, Error}; +use ckb_auth_rs::AlgorithmType; +use clap::{arg, ArgMatches, Command}; +use hex::decode; + +pub struct EthereumLockArgs {} + +impl BlockChainArgs for EthereumLockArgs { + fn block_chain_name(&self) -> &'static str { + "ethereum" + } + + fn reg_parse_args(&self, cmd: Command) -> Command { + cmd + } + fn reg_generate_args(&self, cmd: Command) -> Command { + cmd.arg(arg!(-m --message "Generate message binary for ethereum signing")) + .arg(arg!(--msgfile "Output file")) + } + fn reg_verify_args(&self, cmd: Command) -> Command { + cmd.arg(arg!(-a --address "The ethereum address")) + .arg(arg!(-s --signature "The signature to verify")) + .arg(arg!(-m --message "The signature message")) + } + + fn get_block_chain(&self) -> Box { + Box::new(BitcoinLock {}) + } +} + +pub struct BitcoinLock {} + +impl BlockChain for BitcoinLock { + fn parse(&self, _operate_mathches: &ArgMatches) -> Result<(), Error> { + Err(anyhow!("ethereum does not generate")) + } + + fn generate(&self, operate_mathches: &ArgMatches) -> Result<(), Error> { + let message = decode( + operate_mathches + .get_one::("message") + .expect("Get signature message"), + ) + .expect("Decode message"); + if message.len() != 32 { + return Err(anyhow!("Signature length must be 32")); + } + + let msgfile = operate_mathches + .get_one::("msgfile") + .expect("Get signature message output file"); + + let msgfile = std::path::PathBuf::from(msgfile); + // if msgfile.exists() && msgfile.is_file() { + // std::fs::remove_file(&msgfile); + // } + + std::fs::write(msgfile, message).expect("write message file"); + + Ok(()) + } + + fn verify(&self, operate_mathches: &ArgMatches) -> Result<(), Error> { + let mut address = operate_mathches + .get_one::("address") + .expect("Get address from args") + .clone(); + if address.starts_with("0x") { + address = address[2..].to_string(); + } + let address = decode(&address).expect("decode address"); + + let signature = decode( + operate_mathches + .get_one::("signature") + .expect("Get signature from args"), + ) + .expect("decode ethereum signature"); + + let message = decode( + operate_mathches + .get_one::("message") + .expect("Get message from args"), + ) + .expect("decode ethereum message"); + + if address.len() != 20 { + return Err(anyhow!("ethereum address invalidate")); + } + if signature.len() != 65 { + return Err(anyhow!("ethereum signature size is not 65")); + } + if message.len() != 32 { + return Err(anyhow!("ethereum message size is not 32")); + } + + super::auth_script::run_auth_exec(AlgorithmType::Ethereum, &address, &message, &signature)?; + + println!("Ethereum Signature verification succeeded!"); + Ok(()) + } +} diff --git a/tools/ckb-auth-cli/src/main.rs b/tools/ckb-auth-cli/src/main.rs index 8e9a718..44b8764 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 ethereum; mod litecoin; mod monero; mod ripple; @@ -10,6 +11,7 @@ mod utils; use crate::monero::MoneroLockArgs; use bitcoin::BitcoinLockArgs; use cardano::CardanoLockArgs; +use ethereum::EthereumLockArgs; use litecoin::LitecoinLockArgs; use ripple::RippleLockArgs; use solana::SolanaLockArgs; @@ -83,6 +85,7 @@ fn main() -> Result<(), Error> { Box::new(SolanaLockArgs {}) as Box, Box::new(RippleLockArgs {}) as Box, Box::new(BitcoinLockArgs {}) as Box, + Box::new(EthereumLockArgs {}) as Box, ]; let matches = cli(block_chain_args.as_slice()).get_matches();