Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: Update Signing Message for Funding Lock and Commitment Lock (with Pending HTLC) #17

Merged
merged 2 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions contracts/commitment-lock/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use ckb_std::{
error::SysError,
high_level::{
exec_cell, load_cell, load_cell_capacity, load_cell_data, load_cell_lock, load_cell_type,
load_input_since, load_script, load_tx_hash, load_witness, QueryIter,
load_input_since, load_script, load_transaction, load_witness, QueryIter,
},
since::{EpochNumberWithFraction, LockValue, Since},
};
Expand Down Expand Up @@ -193,7 +193,7 @@ fn auth() -> Result<(), Error> {
];

exec_cell(&AUTH_CODE_HASH, ScriptHashType::Data1, &args).map_err(|_| Error::AuthError)?;
return Ok(());
Ok(())
} else if unlock_type == 0xFE {
// non-pending HTLC unlock process

Expand Down Expand Up @@ -250,7 +250,14 @@ fn auth() -> Result<(), Error> {
}

let raw_since_value = load_input_since(0, Source::GroupInput)?;
let message = load_tx_hash()?;
let message = {
let tx = load_transaction()?
.raw()
.as_builder()
.cell_deps(Default::default())
.build();
blake2b_256(tx.as_slice())
};
let mut signature = [0u8; 65];
let mut pubkey_hash = [0u8; 20];

Expand Down
12 changes: 10 additions & 2 deletions contracts/funding-lock/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#[cfg(test)]
extern crate alloc;

use ckb_hash::blake2b_256;
#[cfg(not(test))]
use ckb_std::default_alloc;
#[cfg(not(test))]
Expand All @@ -16,7 +17,7 @@ use ckb_std::{
ckb_constants::Source,
ckb_types::{bytes::Bytes, core::ScriptHashType, prelude::*},
error::SysError,
high_level::{exec_cell, load_input_since, load_script, load_tx_hash, load_witness},
high_level::{exec_cell, load_input_since, load_script, load_transaction, load_witness},
};
use hex::encode;

Expand Down Expand Up @@ -76,7 +77,14 @@ fn auth() -> Result<(), Error> {
return Err(Error::EmptyWitnessArgsError);
}

let message = load_tx_hash()?;
let message = {
let tx = load_transaction()?
.raw()
.as_builder()
.cell_deps(Default::default())
.build();
blake2b_256(tx.as_slice())
};

let mut pubkey_hash = [0u8; 20];
let script = load_script()?;
Expand Down
45 changes: 30 additions & 15 deletions tests/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use ckb_testtool::{
builtin::ALWAYS_SUCCESS,
ckb_crypto::secp::Generator,
ckb_hash::blake2b_256,
ckb_types::{bytes::Bytes, core::TransactionBuilder, packed::*, prelude::*},
ckb_types::{
bytes::Bytes, core::TransactionBuilder, core::TransactionView, packed::*, prelude::*,
},
context::Context,
};
use musig2::{
Expand Down Expand Up @@ -95,6 +97,19 @@ fn multisig(
aggregated_signature_1.to_bytes().to_vec()
}

/// Compute the message of a transaction
/// We prefer computing the message this way rather than using the transaction hash.
/// This ensures the signature remains valid even if the script code is updated.
fn compute_tx_message(tx: &TransactionView) -> [u8; 32] {
let tx = tx
.data()
.raw()
.as_builder()
.cell_deps(Default::default())
.build();
blake2b_256(tx.as_slice())
}

#[test]
fn test_funding_lock() {
// deploy contract
Expand Down Expand Up @@ -159,7 +174,7 @@ fn test_funding_lock() {
.build();

// sign and add witness
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);
let signature = multisig(sec_key_1, sec_key_2, key_agg_ctx, message);

let witness = [
Expand Down Expand Up @@ -480,7 +495,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.capacity((1000 * BYTE_SHANNONS - payment_amount1 as u64).pack())
.lock(new_lock_script.clone())
.build()];
let outputs_data = vec![Bytes::new()];
let outputs_data = [Bytes::new()];
let tx = TransactionBuilder::default()
.cell_deps(cell_deps.clone())
.inputs(inputs)
Expand All @@ -489,7 +504,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.build();

// sign with remote_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = remote_htlc_key1
.0
Expand Down Expand Up @@ -558,7 +573,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.capacity((1000 * BYTE_SHANNONS - payment_amount1 as u64).pack())
.lock(new_lock_script.clone())
.build()];
let outputs_data = vec![Bytes::new()];
let outputs_data = [Bytes::new()];
let tx = TransactionBuilder::default()
.cell_deps(cell_deps.clone())
.inputs(inputs)
Expand All @@ -567,7 +582,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.build();

// sign with local_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = local_htlc_key1
.0
Expand Down Expand Up @@ -605,7 +620,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.build();

// sign with local_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = local_htlc_key1
.0
Expand Down Expand Up @@ -656,7 +671,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.capacity((1000 * BYTE_SHANNONS - payment_amount2 as u64).pack())
.lock(new_lock_script.clone())
.build()];
let outputs_data = vec![Bytes::new()];
let outputs_data = [Bytes::new()];
let tx = TransactionBuilder::default()
.cell_deps(cell_deps.clone())
.inputs(inputs)
Expand All @@ -665,7 +680,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.build();

// sign with remote_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = remote_htlc_key2
.0
Expand Down Expand Up @@ -705,7 +720,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.capacity((1000 * BYTE_SHANNONS - payment_amount2 as u64).pack())
.lock(new_lock_script.clone())
.build()];
let outputs_data = vec![Bytes::new()];
let outputs_data = [Bytes::new()];
let tx = TransactionBuilder::default()
.cell_deps(cell_deps)
.inputs(inputs)
Expand All @@ -714,7 +729,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
.build();

// sign with local_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = local_htlc_key2
.0
Expand Down Expand Up @@ -931,7 +946,7 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
.build();

// sign with remote_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = remote_htlc_key1
.0
Expand Down Expand Up @@ -981,7 +996,7 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
.build();

// sign with local_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = local_htlc_key1
.0
Expand Down Expand Up @@ -1047,7 +1062,7 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
.build();

// sign with remote_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = remote_htlc_key2
.0
Expand Down Expand Up @@ -1100,7 +1115,7 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
.build();

// sign with local_htlc_pubkey
let message: [u8; 32] = tx.hash().as_slice().try_into().unwrap();
let message: [u8; 32] = compute_tx_message(&tx);

let signature = local_htlc_key2
.0
Expand Down