Skip to content

Commit

Permalink
feat: support lots of flags
Browse files Browse the repository at this point in the history
  • Loading branch information
driftluo committed Apr 25, 2024
1 parent 0e5a278 commit 6c91cd2
Show file tree
Hide file tree
Showing 12 changed files with 898 additions and 208 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ parking_lot = "0.12"
lru = "0.7.1"
dashmap = "5.4"
dyn-clone = "1.0"
faster-hex = "0.9.0"
ripemd = "0.1.3"
sha2 = "0.10.6"
ed25519-dalek = "2.1.1"
openssl = "0.10"

ckb-types = "0.115.0-rc2"
ckb-dao-utils = "0.115.0-rc2"
Expand Down
1 change: 0 additions & 1 deletion rust-toolchain

This file was deleted.

2 changes: 2 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "1.75.0"
5 changes: 5 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ pub const ACP_TYPE_HASH_AGGRON: H256 =
/// cheque withdraw since value
pub const CHEQUE_CELL_SINCE: u64 = 0xA000000000000006;

pub const COMMON_PREFIX: &str = "CKB transaction: 0x";
pub const BTC_PREFIX: &str = "CKB (Bitcoin Layer) transaction: 0x";

pub const SECP256K1_TAG_PUBKEY_UNCOMPRESSED: u8 = 0x04;

#[cfg(test)]
mod test {
use super::*;
Expand Down
344 changes: 202 additions & 142 deletions src/tests/transaction/omnilock.rs

Large diffs are not rendered by default.

156 changes: 146 additions & 10 deletions src/traits/default_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::time::Duration;

use anyhow::anyhow;
use ckb_crypto::secp::Pubkey;
use ed25519_dalek::ed25519::signature::SignerMut;
use lru::LruCache;
use parking_lot::Mutex;
use thiserror::Error;
Expand All @@ -18,20 +19,15 @@ use ckb_types::{
prelude::*,
H160,
};
use openssl::pkey::{PKey, Private};

use super::{
offchain_impls::CollectResult, OffchainCellCollector, OffchainCellDepResolver,
OffchainTransactionDependencyProvider,
};
use crate::rpc::ckb_indexer::{Order, SearchKey, Tip};
use crate::rpc::{CkbRpcClient, IndexerRpcClient};
use crate::traits::{
CellCollector, CellCollectorError, CellDepResolver, CellQueryOptions, HeaderDepResolver,
LiveCell, QueryOrder, Signer, SignerError, TransactionDependencyError,
TransactionDependencyProvider,
use crate::util::{
get_max_mature_number, iso9796_2_batch_sign, serialize_signature, zeroize_privkey,
};
use crate::types::ScriptId;
use crate::util::{get_max_mature_number, serialize_signature, zeroize_privkey};
use crate::SECP256K1;
use crate::{
constants::{
Expand All @@ -40,6 +36,24 @@ use crate::{
},
util::keccak160,
};
use crate::{
rpc::ckb_indexer::{Order, SearchKey, Tip},
unlock::omni_lock::BTCSignVtype,
util::btc_auth,
};
use crate::{
rpc::{CkbRpcClient, IndexerRpcClient},
util::eos_auth,
};
use crate::{
traits::{
CellCollector, CellCollectorError, CellDepResolver, CellQueryOptions, HeaderDepResolver,
LiveCell, QueryOrder, Signer, SignerError, TransactionDependencyError,
TransactionDependencyProvider,
},
util::blake160,
};
use crate::{types::ScriptId, util::rsa_sign};
use ckb_resource::{
CODE_HASH_DAO, CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
CODE_HASH_SECP256K1_BLAKE160_SIGHASH_ALL,
Expand Down Expand Up @@ -79,7 +93,7 @@ impl DefaultCellDepResolver {
.map(|(tx_index, tx)| {
tx.outputs()
.into_iter()
.zip(tx.outputs_data().into_iter())
.zip(tx.outputs_data())
.enumerate()
.map(|(index, (output, data))| {
if tx_index == SIGHASH_OUTPUT_LOC.0 && index == SIGHASH_OUTPUT_LOC.1 {
Expand Down Expand Up @@ -569,7 +583,7 @@ impl TransactionDependencyProvider for DefaultTransactionDependencyProvider {
}
}

/// A signer use secp256k1 raw key, the id is `blake160(pubkey)`.
/// A signer use secp256k1 raw key.
#[derive(Default, Clone)]
pub struct SecpCkbRawKeySigner {
keys: HashMap<H160, secp256k1::SecretKey>,
Expand All @@ -579,13 +593,15 @@ impl SecpCkbRawKeySigner {
pub fn new(keys: HashMap<H160, secp256k1::SecretKey>) -> SecpCkbRawKeySigner {
SecpCkbRawKeySigner { keys }
}

pub fn new_with_secret_keys(keys: Vec<secp256k1::SecretKey>) -> SecpCkbRawKeySigner {
let mut signer = SecpCkbRawKeySigner::default();
for key in keys {
signer.add_secret_key(key);
}
signer
}

pub fn add_secret_key(&mut self, key: secp256k1::SecretKey) {
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &key);
let hash160 = H160::from_slice(&blake2b_256(&pubkey.serialize()[..])[0..20])
Expand All @@ -607,6 +623,34 @@ impl SecpCkbRawKeySigner {
let hash160 = keccak160(Pubkey::from(pubkey).as_ref());
self.keys.insert(hash160, key);
}

pub fn new_with_btc_secret_key(keys: Vec<secp256k1::SecretKey>, vtype: BTCSignVtype) -> Self {
let mut signer = SecpCkbRawKeySigner::default();
for key in keys {
signer.add_btc_secret_key(key, vtype);
}
signer
}

pub fn add_btc_secret_key(&mut self, key: secp256k1::SecretKey, vtype: BTCSignVtype) {
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &key);
let hash160 = btc_auth(&pubkey.into(), vtype);
self.keys.insert(hash160.into(), key);
}

pub fn new_with_eos_secret_key(keys: Vec<secp256k1::SecretKey>, vtype: BTCSignVtype) -> Self {
let mut signer = SecpCkbRawKeySigner::default();
for key in keys {
signer.add_eos_secret_key(key, vtype);
}
signer
}

pub fn add_eos_secret_key(&mut self, key: secp256k1::SecretKey, vtype: BTCSignVtype) {
let pubkey = secp256k1::PublicKey::from_secret_key(&SECP256K1, &key);
let hash160 = eos_auth(&pubkey.into(), vtype);
self.keys.insert(hash160.into(), key);
}
}

impl Signer for SecpCkbRawKeySigner {
Expand Down Expand Up @@ -649,6 +693,98 @@ impl Drop for SecpCkbRawKeySigner {
}
}
}

pub struct RsaSigner {
key: PKey<Private>,
use_rsa: bool,
use_iso9796_2: bool,
}

impl RsaSigner {
pub fn new(key: PKey<Private>, use_rsa: bool, use_iso9796_2: bool) -> Self {
Self {
key,
use_rsa,
use_iso9796_2,
}
}
}

impl Signer for RsaSigner {
fn match_id(&self, id: &[u8]) -> bool {
id.len() == 20 && id == blake160(&self.key.public_key_to_pem().unwrap()).as_bytes()
}

fn sign(
&self,
id: &[u8],
message: &[u8],
_recoverable: bool,
_tx: &TransactionView,
) -> Result<Bytes, SignerError> {
if !self.match_id(id) {
return Err(SignerError::IdNotFound);
}
if message.len() != 32 {
return Err(SignerError::InvalidMessage(format!(
"expected length: 32, got: {}",
message.len()
)));
}
if self.use_rsa {
Ok(rsa_sign(message, &self.key).into())
} else if self.use_iso9796_2 {
Ok(iso9796_2_batch_sign(message, &self.key).into())
} else {
Ok(Default::default())
}
}
}

/// A signer use ed25519 raw key
#[derive(Clone)]
pub struct Ed25519Signer {
key: ed25519_dalek::SigningKey,
}

impl Ed25519Signer {
pub fn new(key: ed25519_dalek::SigningKey) -> Self {
Self { key }
}
}

impl Signer for Ed25519Signer {
fn match_id(&self, id: &[u8]) -> bool {
id.len() == 20 && blake160(&self.key.verifying_key().as_bytes()[..]).as_bytes() == id
}

fn sign(
&self,
id: &[u8],
message: &[u8],
_recoverable: bool,
_tx: &TransactionView,
) -> Result<Bytes, SignerError> {
if !self.match_id(id) {
return Err(SignerError::IdNotFound);
}
if message.len() != 83 {
return Err(SignerError::InvalidMessage(format!(
"expected length: 83, got: {}",
message.len()
)));
}

let sig = self.key.clone().sign(message);

let verifying_key = self.key.verifying_key();
// 64 + 32
let mut sig_plus_pubkey = sig.to_vec();
sig_plus_pubkey.extend(verifying_key.as_bytes());
Ok(Bytes::from(sig_plus_pubkey))
}
}

#[cfg(test)]
mod anyhow_tests {
use anyhow::anyhow;
Expand Down
20 changes: 20 additions & 0 deletions src/transaction/signer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use ckb_types::{
packed::{CellOutput, OutPoint},
H256,
};
use openssl::pkey::{PKey, Private};
use std::collections::HashMap;

use crate::{
Expand Down Expand Up @@ -82,6 +83,25 @@ impl SignContexts {
}
}

pub fn new_omnilock_solana(
key: ed25519_dalek::SigningKey,
omnilock_config: OmniLockConfig,
) -> Self {
let omnilock_context =
omnilock::OmnilockSignerContext::new_with_ed25519_key(key, omnilock_config);
Self {
contexts: vec![Box::new(omnilock_context)],
}
}

pub fn new_omnilock_dl(key: PKey<Private>, omnilock_config: OmniLockConfig) -> Self {
let omnilock_context =
omnilock::OmnilockSignerContext::new_with_rsa_key(key, omnilock_config);
Self {
contexts: vec![Box::new(omnilock_context)],
}
}

#[inline]
pub fn add_context(&mut self, context: Box<dyn SignContext>) {
self.contexts.push(context);
Expand Down
66 changes: 57 additions & 9 deletions src/transaction/signer/omnilock.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::collections::HashMap;

use ckb_types::{core, packed};
use openssl::pkey::{PKey, Private};

use crate::{
traits::SecpCkbRawKeySigner,
traits::{
default_impls::{Ed25519Signer, RsaSigner},
SecpCkbRawKeySigner, Signer,
},
unlock::{
OmniLockConfig, OmniLockScriptSigner, OmniLockUnlocker, OmniUnlockMode, ScriptUnlocker,
UnlockError,
IdentityFlag, OmniLockConfig, OmniLockScriptSigner, OmniLockUnlocker, OmniUnlockMode,
ScriptUnlocker, UnlockError,
},
};

Expand All @@ -16,6 +20,8 @@ pub struct OmnilockSigner {}

pub struct OmnilockSignerContext {
keys: Vec<secp256k1::SecretKey>,
ed25519_key: Option<ed25519_dalek::SigningKey>,
rsa_key: Option<PKey<Private>>,
cfg: OmniLockConfig,
unlock_mode: OmniUnlockMode,
}
Expand All @@ -24,19 +30,61 @@ impl OmnilockSignerContext {
pub fn new(keys: Vec<secp256k1::SecretKey>, cfg: OmniLockConfig) -> Self {
Self {
keys,
ed25519_key: None,
rsa_key: None,
cfg,
unlock_mode: OmniUnlockMode::Normal,
}
}

pub fn new_with_ed25519_key(key: ed25519_dalek::SigningKey, cfg: OmniLockConfig) -> Self {
Self {
keys: Default::default(),
ed25519_key: Some(key),
rsa_key: None,
cfg,
unlock_mode: OmniUnlockMode::Normal,
}
}

pub fn new_with_rsa_key(key: PKey<Private>, cfg: OmniLockConfig) -> Self {
Self {
keys: Default::default(),
ed25519_key: None,
rsa_key: Some(key),
cfg,
unlock_mode: OmniUnlockMode::Normal,
}
}

pub fn build_omnilock_unlocker(&self) -> OmniLockUnlocker {
let signer = if self.cfg.is_ethereum() {
SecpCkbRawKeySigner::new_with_ethereum_secret_keys(self.keys.clone())
} else {
SecpCkbRawKeySigner::new_with_secret_keys(self.keys.clone())
let signer: Box<dyn Signer> = match self.cfg.id().flag() {
IdentityFlag::Ethereum | IdentityFlag::EthereumDisplaying | IdentityFlag::Tron => {
Box::new(SecpCkbRawKeySigner::new_with_ethereum_secret_keys(
self.keys.clone(),
))
}
IdentityFlag::Bitcoin | IdentityFlag::Dogecoin => {
Box::new(SecpCkbRawKeySigner::new_with_btc_secret_key(
self.keys.clone(),
self.cfg.btc_sign_vtype,
))
}
IdentityFlag::Eos => Box::new(SecpCkbRawKeySigner::new_with_eos_secret_key(
self.keys.clone(),
self.cfg.btc_sign_vtype,
)),
IdentityFlag::Solana => Box::new(Ed25519Signer::new(
self.ed25519_key.clone().expect("must have ed25519"),
)),
IdentityFlag::Dl => Box::new(RsaSigner::new(
self.rsa_key.clone().expect("muse have rsa"),
self.cfg.use_rsa,
self.cfg.use_iso9796_2,
)),
_ => Box::new(SecpCkbRawKeySigner::new_with_secret_keys(self.keys.clone())),
};
let omnilock_signer =
OmniLockScriptSigner::new(Box::new(signer), self.cfg.clone(), self.unlock_mode);
let omnilock_signer = OmniLockScriptSigner::new(signer, self.cfg.clone(), self.unlock_mode);
OmniLockUnlocker::new(omnilock_signer, self.cfg.clone())
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/tx_builder/dao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,7 @@ impl TxBuilder for DaoWithdrawBuilder {
inputs.push(input);
witnesses.push(witness.pack());
}
header_deps.extend(
prepare_block_hashes
.into_iter()
.collect::<HashSet<_>>()
.into_iter(),
);
header_deps.extend(prepare_block_hashes.into_iter().collect::<HashSet<_>>());

let (outputs, outputs_data) = match &self.receiver {
DaoWithdrawReceiver::LockScript { script, fee_rate } => {
Expand Down
Loading

0 comments on commit 6c91cd2

Please sign in to comment.