From f3d7b5d85018980c4e9f963566cad503dff64b53 Mon Sep 17 00:00:00 2001 From: joii2020 <87224197+joii2020@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:41:05 +0800 Subject: [PATCH] Support Dogecoin (#16) * ckb-auth-cli support dogecoin * Add dogecoin doc --- README.md | 2 +- docs/dogecoin.md | 67 +++++++++++++ tools/ckb-auth-cli/Cargo.lock | 64 +++++++++++- tools/ckb-auth-cli/Cargo.toml | 1 + tools/ckb-auth-cli/src/bin/ckb-auth-cli.rs | 5 +- .../src/chain_command/dogecoin.rs | 98 +++++++++++++++++++ tools/ckb-auth-cli/src/chain_command/mod.rs | 2 + 7 files changed, 234 insertions(+), 5 deletions(-) create mode 100644 docs/dogecoin.md create mode 100644 tools/ckb-auth-cli/src/chain_command/dogecoin.rs diff --git a/README.md b/README.md index 6d6475e..2d0c3cb 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The following blockchains are supported: * [Ethereum](./docs/ethereum.md) * [EOS](./docs/eos.md) * [Tron](./docs/tron.md) -* Dogecoin +* [Dogecoin](./docs/dogecoin.md) * CKB * [Litecoin](./docs/litecoin.md) * [Cardano](./docs/cardano.md) diff --git a/docs/dogecoin.md b/docs/dogecoin.md new file mode 100644 index 0000000..4418f82 --- /dev/null +++ b/docs/dogecoin.md @@ -0,0 +1,67 @@ +# [Dogecoin](../README.md) + +To work with Dogecoin, utilize the official command-line tool: [DogecoinCore](https://github.com/dogecoin/dogecoin/tree/v1.14.6). + +Dogecoin shares many similarities with [Bitcoin](./bitcoin.md), including its signature algorithm and command-line tools. Here, we will focus on the distinctive aspects that set Dogecoin apart. + +## Installation and Configuration +[Download](https://github.com/dogecoin/dogecoin/releases/tag/v1.14.6) +- It's essential to note that, much like `BitcoinCore` on Mac, Dogecoin provides GUI tools exclusively. +- For configuration, you can use the official default settings. If you prefer not to synchronize with online nodes, you can add `proxy=127.0.0.1:12345` to the configuration, using a non-existent proxy. + +Start Dogecoin with the following command: +``` +./dogecoind -daemonwait +``` + +## Generate a Key + +When using dogecoin-cli for the first time, the `getaddressesbyaccount` command will automatically generate a new key group. Account information is stored in `wallet.dat`. + +```bash +./dogecoin-cli getaddressesbyaccount "" +``` + +``` +[ + "DNF59P3dX2S2i188aPfBfL4aecs9gWtBt8" +] +``` + +A Dogecoin address always begins with the letter `D`, followed by content encoded in Base58, which includes the `public key hash` and a `checksum`. [You can find the code to parse and check addresses here](../tools/ckb-auth-cli/src/chain_command/dogecoin.rs#L52). + +## Sign + +Dogecoin Core supports signing and verifying messages. + +```bash +./dogecoin-cli signmessage DNF59P3dX2S2i188aPfBfL4aecs9gWtBt8 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +``` + +Output: +``` +IIu/kxASl/W/5o3bjTD4KKBCQKcsDPUdp0+1Xu4vy0FhcpSfsIPu5Mi90VV0FGsN2gdlUvQFswTI886CeKNp7So= +``` + +The output signature data is Base58 encoded and can be used directly in ckb-auth. + +To verify with `Dogecoin Core`: + +```bash +./dogecoin-cli verifymessage DNF59P3dX2S2i188aPfBfL4aecs9gWtBt8 IIu/kxASl/W/5o3bjTD4KKBCQKcsDPUdp0+1Xu4vy0FhcpSfsIPu5Mi90VV0FGsN2gdlUvQFswTI886CeKNp7So= 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +``` + +Output: +``` +true +``` + +## Verify + +To verify in ckb-auth-cli: + +```bash +ckb-auth-cli dogecoin verify -a DNF59P3dX2S2i188aPfBfL4aecs9gWtBt8 -s IIu/kxASl/W/5o3bjTD4KKBCQKcsDPUdp0+1Xu4vy0FhcpSfsIPu5Mi90VV0FGsN2gdlUvQFswTI886CeKNp7So= -m 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff +``` + +Verification in Dogecoin is quite similar to Bitcoin, with the exception of address handling. For the most part, Bitcoin code can be used. \ No newline at end of file diff --git a/tools/ckb-auth-cli/Cargo.lock b/tools/ckb-auth-cli/Cargo.lock index 81924f8..10528fb 100644 --- a/tools/ckb-auth-cli/Cargo.lock +++ b/tools/ckb-auth-cli/Cargo.lock @@ -109,6 +109,12 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bindgen" version = "0.65.1" @@ -144,6 +150,34 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" +dependencies = [ + "bech32", + "bitcoin-private", + "bitcoin_hashes", + "hex_lit", + "secp256k1 0.27.0", +] + +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -269,6 +303,7 @@ dependencies = [ "anyhow", "base58-monero", "base64", + "bitcoin", "bs58", "ckb-auth-rs", "ckb-hash", @@ -340,7 +375,7 @@ dependencies = [ "faster-hex", "lazy_static", "rand 0.7.3", - "secp256k1", + "secp256k1 0.24.3", "thiserror", ] @@ -968,6 +1003,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -1638,7 +1679,17 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ - "secp256k1-sys", + "secp256k1-sys 0.6.1", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes", + "secp256k1-sys 0.8.1", ] [[package]] @@ -1650,6 +1701,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "0.9.0" diff --git a/tools/ckb-auth-cli/Cargo.toml b/tools/ckb-auth-cli/Cargo.toml index b852f95..49157ce 100644 --- a/tools/ckb-auth-cli/Cargo.toml +++ b/tools/ckb-auth-cli/Cargo.toml @@ -22,3 +22,4 @@ monero = { version = "0.18.2", features = ["serde"] } base58-monero = "1.0.0" mbedtls = "0.8.1" sha2 = "0.10.6" +bitcoin = "0.30.0" \ No newline at end of file diff --git a/tools/ckb-auth-cli/src/bin/ckb-auth-cli.rs b/tools/ckb-auth-cli/src/bin/ckb-auth-cli.rs index cda8220..2ad7f0a 100644 --- a/tools/ckb-auth-cli/src/bin/ckb-auth-cli.rs +++ b/tools/ckb-auth-cli/src/bin/ckb-auth-cli.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Error}; use ckb_auth_cli::{ chain_command::{ - BitcoinLockArgs, CardanoLockArgs, EosLockArgs, EthereumLockArgs, LitecoinLockArgs, - MoneroLockArgs, RippleLockArgs, SolanaLockArgs, TronLockArgs, + BitcoinLockArgs, CardanoLockArgs, DogecoinLockArgs, EosLockArgs, EthereumLockArgs, + LitecoinLockArgs, MoneroLockArgs, RippleLockArgs, SolanaLockArgs, TronLockArgs, }, BlockChainArgs, }; @@ -62,6 +62,7 @@ fn main() -> Result<(), Error> { Box::new(EthereumLockArgs {}) as Box, Box::new(EosLockArgs {}) as Box, Box::new(TronLockArgs {}) as Box, + Box::new(DogecoinLockArgs {}) as Box, ]; let matches = cli(block_chain_args.as_slice()).get_matches(); diff --git a/tools/ckb-auth-cli/src/chain_command/dogecoin.rs b/tools/ckb-auth-cli/src/chain_command/dogecoin.rs new file mode 100644 index 0000000..42e314f --- /dev/null +++ b/tools/ckb-auth-cli/src/chain_command/dogecoin.rs @@ -0,0 +1,98 @@ +use crate::{ + auth_script::run_auth_exec, + utils::{calculate_sha256, decode_string}, +}; +use crate::{BlockChain, BlockChainArgs}; +use anyhow::{anyhow, Error}; +use ckb_auth_rs::AuthAlgorithmIdType; +use clap::{arg, ArgMatches, Command}; + +pub struct DogecoinLockArgs {} + +impl BlockChainArgs for DogecoinLockArgs { + fn block_chain_name(&self) -> &'static str { + "dogecoin" + } + + 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!(-a --address "The dogecoin address")) + .arg(arg!(-s --signature "The signature to verify")) + .arg(arg!(-m --message "The signature message")) + } + + fn get_block_chain(&self) -> Box { + Box::new(DogecoinLock {}) + } +} + +pub struct DogecoinLock {} + +impl BlockChain for DogecoinLock { + fn parse(&self, _operate_mathches: &ArgMatches) -> Result<(), Error> { + Err(anyhow!("dogecoin does not parse")) + } + + fn generate(&self, _operate_mathches: &ArgMatches) -> Result<(), Error> { + Err(anyhow!("dogecoin does not generate")) + } + + fn verify(&self, operate_mathches: &ArgMatches) -> Result<(), Error> { + let address = operate_mathches + .get_one::("address") + .expect("Get address from args"); + let address = bs58::decode(&address).into_vec().expect("get base58"); + + // https://github.com/dogecoin/dogecoin/blob/v1.14.6/src/chainparams.cpp#L167 + if address[0] != 30 { + return Err(anyhow!("The first byte of address is not 30")); + } + + let checksum = calculate_sha256(&calculate_sha256(&address[..21])); + if checksum[..4] != address[21..] { + return Err(anyhow!("Address Checksum failed,")); + } + + let signature = decode_string( + operate_mathches + .get_one::("signature") + .expect("Get signature from args"), + "base64", + ) + .expect("decode signature from base64 string"); + + let message = hex::decode( + operate_mathches + .get_one::("message") + .expect("Get message from args"), + ) + .expect("decode message"); + + if address.len() < 21 { + return Err(anyhow!("dogecoin address invalidate")); + } + if signature.len() != 65 { + return Err(anyhow!("dogecoin signature size is not 65")); + } + if message.len() != 32 { + return Err(anyhow!("dogecoin message size is not 32")); + } + + let pubkey_hash = &address[1..21]; + + run_auth_exec( + AuthAlgorithmIdType::Dogecoin, + pubkey_hash, + &message, + &signature, + )?; + + println!("Success"); + Ok(()) + } +} diff --git a/tools/ckb-auth-cli/src/chain_command/mod.rs b/tools/ckb-auth-cli/src/chain_command/mod.rs index d8f8cf2..69ddf50 100644 --- a/tools/ckb-auth-cli/src/chain_command/mod.rs +++ b/tools/ckb-auth-cli/src/chain_command/mod.rs @@ -1,5 +1,6 @@ mod bitcoin; mod cardano; +mod dogecoin; mod eos; mod ethereum; mod litecoin; @@ -11,6 +12,7 @@ mod tron; pub use self::monero::{MoneroLock, MoneroLockArgs}; pub use bitcoin::{BitcoinLock, BitcoinLockArgs}; pub use cardano::{CardanoLock, CardanoLockArgs}; +pub use dogecoin::{DogecoinLock, DogecoinLockArgs}; pub use eos::{EosLock, EosLockArgs}; pub use ethereum::{EthereumLock, EthereumLockArgs}; pub use litecoin::{LitecoinLock, LitecoinLockArgs};