Skip to content

Commit

Permalink
Add first test
Browse files Browse the repository at this point in the history
  • Loading branch information
mohanson committed Jul 17, 2024
1 parent ce4856a commit ecdc721
Show file tree
Hide file tree
Showing 10 changed files with 1,229 additions and 330 deletions.
100 changes: 60 additions & 40 deletions contracts/ccc-btc-lock/src/entry.rs
Original file line number Diff line number Diff line change
@@ -1,65 +1,85 @@
use crate::error::Error;
use alloc::{string::String, vec::Vec};
use ckb_lock_helper::{
constant::{BTC_PREFIX, PREFIX, SUFFIX},
generate_sighash_all,
};
use alloc::vec::Vec;
use ckb_lock_helper::{generate_sighash_all, println_hex};
use ckb_std::{
ckb_constants::Source,
high_level::{load_script, load_witness_args},
};
use k256::ecdsa::{RecoveryId, Signature, VerifyingKey};
use ripemd::Ripemd160;
use sha2::{Digest, Sha256};
use ripemd::{Digest, Ripemd160};
use sha2::Sha256;

fn ripemd160_sha256(msg: &[u8]) -> [u8; 20] {
ripemd160(&sha256(msg))
}

fn ripemd160(message: &[u8]) -> [u8; 20] {
let mut hasher = Ripemd160::new();
hasher.update(message);
hasher.finalize().into()
}

fn sha256(msg: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(msg);
hasher.finalize().into()
}

fn sha256_sha256(msg: &[u8]) -> [u8; 32] {
sha256(&sha256(msg))
}

fn message_hash(msg: &str) -> [u8; 32] {
// Only 32-bytes hex representation of the hash is allowed.
assert_eq!(msg.len(), 64);
// Text used to signify that a signed message follows and to prevent inadvertently signing a transaction.
const CKB_PREFIX: &str = "Signing a CKB transaction: 0x";
const CKB_SUFFIX: &str = "\n\nIMPORTANT: Please verify the integrity and authenticity of connected BTC wallet before signing this message\n";
const BTC_PREFIX: &str = "Bitcoin Signed Message:\n";
let mut data: Vec<u8> = Vec::new();
assert_eq!(BTC_PREFIX.len(), 24);
data.push(24);
data.extend(BTC_PREFIX.as_bytes());
data.push((CKB_PREFIX.len() + msg.len() + CKB_SUFFIX.len()) as u8);
data.extend(CKB_PREFIX.as_bytes());
data.extend(msg.as_bytes());
data.extend(CKB_SUFFIX.as_bytes());
sha256_sha256(&data)
}

pub fn entry() -> Result<(), Error> {
let script = load_script()?;
let pubkey_hash = script.args().raw_data();
if pubkey_hash.len() != 20 {
let pubkey_hash_expect = script.args().raw_data();
if pubkey_hash_expect.len() != 20 {
return Err(Error::WrongPubkeyHash);
}

let mut to_be_hashed: Vec<u8> = Default::default();
assert_eq!(BTC_PREFIX.len(), 24);
to_be_hashed.push(BTC_PREFIX.len() as u8);
to_be_hashed.extend(BTC_PREFIX.as_bytes());

let sighash_all = generate_sighash_all()?;
let sighash_all_hex = hex::encode(&sighash_all);
let message1 = String::from(PREFIX) + &sighash_all_hex + SUFFIX;

assert!(message1.len() < 256);
to_be_hashed.push(message1.len() as u8);
to_be_hashed.extend(message1.into_bytes());

// Double SHA-256 from bitcoin
let msg = Sha256::digest(&Sha256::digest(&to_be_hashed));

let digest_hash = message_hash(&sighash_all_hex);
let witness_args = load_witness_args(0, Source::GroupInput)?;
let sig = witness_args
let sig_raw = witness_args
.lock()
.to_opt()
.ok_or(Error::WrongSignatureFormat)?
.raw_data();

if sig.len() != 65 {
if sig_raw.len() != 65 {
return Err(Error::WrongSignatureFormat);
}
let rec_id = match sig[0] {
31 | 32 | 33 | 34 => sig[0] - 31,
39 | 40 | 41 | 42 => sig[0] - 39,
_ => sig[0],
let rec_id = match sig_raw[0] {
31 | 32 | 33 | 34 => sig_raw[0] - 31,
39 | 40 | 41 | 42 => sig_raw[0] - 39,
_ => sig_raw[0],
};
let rec_id = RecoveryId::try_from(rec_id).map_err(|_| Error::InvalidRecoverId)?;
let signature = Signature::from_slice(&sig[1..]).map_err(|_| Error::WrongSignatureFormat)?;
let recovered_key = VerifyingKey::recover_from_prehash(&msg, &signature, rec_id)
.map_err(|_| Error::CanNotRecover)?;
// TODO: double check its format
let recovered_key_bytes = recovered_key.to_sec1_bytes();
// RIPEMD160 over SHA-256 for pubkey hashing
let pubkey_hash_result: [u8; 20] =
Ripemd160::digest(&Sha256::digest(&recovered_key_bytes)).into();
if pubkey_hash_result.as_ref() != pubkey_hash.as_ref() {
let sig = Signature::from_slice(&sig_raw[1..]).map_err(|_| Error::WrongSignatureFormat)?;
let pubkey_result = VerifyingKey::recover_from_prehash(&digest_hash, &sig, rec_id)
.map_err(|_| Error::CanNotRecover)?
.to_sec1_bytes();
assert!(pubkey_result.len() == 33);
let pubkey_hash_result = ripemd160_sha256(&pubkey_result);
println_hex("pubkey_result", pubkey_hash_result.as_ref());
println_hex("pubkey_expect", pubkey_hash_expect.as_ref());
if pubkey_hash_result.as_ref() != pubkey_hash_expect.as_ref() {
return Err(Error::PubkeyHashMismatched);
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/ckb-lock-helper/src/blake2b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn blake160(data: &[u8]) -> [u8; 20] {
blake2b.update(data);
blake2b.finalize(&mut hash);
let mut ret = [0u8; 20];
(&mut ret).copy_from_slice(&hash[0..20]);
ret.copy_from_slice(&hash[0..20]);
ret
}

Expand Down
3 changes: 0 additions & 3 deletions crates/ckb-lock-helper/src/constant.rs

This file was deleted.

8 changes: 6 additions & 2 deletions crates/ckb-lock-helper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#![no_main]
extern crate alloc;
pub mod blake2b;
pub mod constant;
pub mod error;

use crate::blake2b::new_blake2b_stat;
Expand All @@ -15,6 +14,10 @@ use ckb_std::debug;
use ckb_std::high_level::{load_tx_hash, load_witness, load_witness_args};
use ckb_std::syscalls::{load_input_by_field, SysError};

pub fn println_hex(name: &str, data: &[u8]) {
debug!("{}(len={}): {}", name, data.len(), hex::encode(data));
}

pub fn generate_sighash_all() -> Result<[u8; 32], Error> {
let mut blake2b_ctx = new_blake2b_stat();
let tx_hash = load_tx_hash()?;
Expand Down Expand Up @@ -58,8 +61,9 @@ pub fn generate_sighash_all() -> Result<[u8; 32], Error> {
}
}
let mut msg = [0u8; 32];
debug!("Hashed {} bytes in sighash_all", blake2b_ctx.count());
debug!("hashed {} bytes in sighash_all", blake2b_ctx.count());
blake2b_ctx.finalize(&mut msg);
println_hex("sighash_all_digest", &msg);
Ok(msg)
}

Expand Down
Loading

0 comments on commit ecdc721

Please sign in to comment.