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

feat: add payment hash type #6

Merged
merged 1 commit into from
Jun 28, 2024
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions contracts/commitment-lock/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
ckb-std = "0.15"
ckb-hash = { version = "0.114.0", default-features = false, features = ["ckb-contract"] }
hex = { version = "0.4", default-features = false, features = ["alloc"]}
sha2 = { version = "0.10", default-features = false }

[build-dependencies]
ckb-gen-types = "0.114.0"
2 changes: 1 addition & 1 deletion contracts/commitment-lock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The lock script args is the hash result of blake160(local_delay_epoch || local_d
- `local_delay_pubkey_hash`: 20 bytes, hash result of blake160(local_delay_pubkey)
- `revocation_pubkey_hash`: 20 bytes, hash result of blake160(revocation_pubkey)
- `pending_htlc`: A group of pending HTLCS, each HTLC is 85 bytes, contains:
- `htlc_type`: 1 byte, 0x00 for offered HTLC, 0x01 for received HTLC
- `htlc_type`: 1 byte, high 7 bits for payment hash type (0000000 for blake2b, 0000001 for sha256), low 1 bit for offered or received type (0 for offered HTLC, 1 for received HTLC)
- `payment_amount`: 16 bytes, u128 in little endian
- `payment_hash`: 20 bytes
- `remote_htlc_pubkey_hash`: 20 bytes, hash result of blake160(remote_htlc_pubkey)
Expand Down
124 changes: 80 additions & 44 deletions contracts/commitment-lock/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use ckb_std::{
since::Since,
};
use hex::encode;
use sha2::{Digest, Sha256};

include!(concat!(env!("OUT_DIR"), "/auth_code_hash.rs"));

Expand Down Expand Up @@ -80,11 +81,33 @@ const UNLOCK_WITH_SIGNATURE_LEN: usize = 66;
const PREIMAGE_LEN: usize = 32;
const MIN_WITNESS_LEN: usize = MIN_WITNESS_SCRIPT_LEN + UNLOCK_WITH_SIGNATURE_LEN;

enum HtlcType {
Offered,
Received,
}

enum PaymentHashType {
Blake2b,
Sha256,
}

struct Htlc<'a>(&'a [u8]);

impl<'a> Htlc<'a> {
pub fn htlc_type(&self) -> u8 {
self.0[0]
pub fn htlc_type(&self) -> HtlcType {
if self.0[0] & 0b00000001 == 0 {
HtlcType::Offered
} else {
HtlcType::Received
}
}

pub fn payment_hash_type(&self) -> PaymentHashType {
if (self.0[0] >> 1) & 0b0000001 == 0 {
PaymentHashType::Blake2b
} else {
PaymentHashType::Sha256
}
}

pub fn payment_amount(&self) -> u128 {
Expand Down Expand Up @@ -202,54 +225,67 @@ fn auth() -> Result<(), Error> {
{
let htlc = Htlc(htlc_script);
if unlock_htlc == i {
if htlc.htlc_type() == 0 {
// offered HTLC
let raw_since_value = load_input_since(0, Source::GroupInput)?;
if raw_since_value == 0 {
// when input since is 0, it means the unlock logic is for remote_htlc pubkey and preimage
if preimage
.map(|p| htlc.payment_hash() != &blake2b_256(p)[0..20])
.unwrap_or(true)
{
return Err(Error::PreimageError);
}
new_amount -= htlc.payment_amount();
pubkey_hash.copy_from_slice(htlc.remote_htlc_pubkey_hash());
} else {
// when input since is not 0, it means the unlock logic is for local_htlc pubkey and htlc expiry
let since = Since::new(raw_since_value);
let htlc_expiry = Since::new(htlc.htlc_expiry());
if since >= htlc_expiry {
pubkey_hash.copy_from_slice(htlc.local_htlc_pubkey_hash());
match htlc.htlc_type() {
HtlcType::Offered => {
let raw_since_value = load_input_since(0, Source::GroupInput)?;
if raw_since_value == 0 {
// when input since is 0, it means the unlock logic is for remote_htlc pubkey and preimage
if preimage
.map(|p| match htlc.payment_hash_type() {
PaymentHashType::Blake2b => {
htlc.payment_hash() != &blake2b_256(p)[0..20]
}
PaymentHashType::Sha256 => {
htlc.payment_hash() != &Sha256::digest(p)[0..20]
}
})
.unwrap_or(true)
{
return Err(Error::PreimageError);
}
new_amount -= htlc.payment_amount();
pubkey_hash.copy_from_slice(htlc.remote_htlc_pubkey_hash());
} else {
return Err(Error::InvalidSince);
// when input since is not 0, it means the unlock logic is for local_htlc pubkey and htlc expiry
let since = Since::new(raw_since_value);
let htlc_expiry = Since::new(htlc.htlc_expiry());
if since >= htlc_expiry {
pubkey_hash.copy_from_slice(htlc.local_htlc_pubkey_hash());
} else {
return Err(Error::InvalidSince);
}
}
}
} else if htlc.htlc_type() == 1 {
// received HTLC
let raw_since_value = load_input_since(0, Source::GroupInput)?;
if raw_since_value == 0 {
// when input since is 0, it means the unlock logic is for local_htlc pubkey and preimage
if preimage
.map(|p| htlc.payment_hash() != &blake2b_256(p)[0..20])
.unwrap_or(true)
{
return Err(Error::PreimageError);
}
pubkey_hash.copy_from_slice(htlc.local_htlc_pubkey_hash());
} else {
// when input since is not 0, it means the unlock logic is for remote_htlc pubkey and htlc expiry
let since = Since::new(raw_since_value);
let htlc_expiry = Since::new(htlc.htlc_expiry());
if since >= htlc_expiry {
new_amount -= htlc.payment_amount();
pubkey_hash.copy_from_slice(htlc.remote_htlc_pubkey_hash());
HtlcType::Received => {
let raw_since_value = load_input_since(0, Source::GroupInput)?;
if raw_since_value == 0 {
// when input since is 0, it means the unlock logic is for local_htlc pubkey and preimage
if preimage
.map(|p| match htlc.payment_hash_type() {
PaymentHashType::Blake2b => {
htlc.payment_hash() != &blake2b_256(p)[0..20]
}
PaymentHashType::Sha256 => {
htlc.payment_hash() != &Sha256::digest(p)[0..20]
}
})
.unwrap_or(true)
{
return Err(Error::PreimageError);
}
pubkey_hash.copy_from_slice(htlc.local_htlc_pubkey_hash());
} else {
return Err(Error::InvalidSince);
// when input since is not 0, it means the unlock logic is for remote_htlc pubkey and htlc expiry
let since = Since::new(raw_since_value);
let htlc_expiry = Since::new(htlc.htlc_expiry());
if since >= htlc_expiry {
new_amount -= htlc.payment_amount();
pubkey_hash.copy_from_slice(htlc.remote_htlc_pubkey_hash());
} else {
return Err(Error::InvalidSince);
}
}
}
} else {
return Err(Error::InvalidHtlcType);
}
} else {
new_witness_script.push(htlc_script);
Expand Down
1 change: 1 addition & 0 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ ckb-std = "0.15"
serde_json = "1.0"
secp256k1 = { version = "0.28", features = ["rand-std"] }
musig2 = "0.0.11"
sha2 = "0.10"
21 changes: 11 additions & 10 deletions tests/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use secp256k1::{
rand::{self, RngCore},
PublicKey, Secp256k1, SecretKey,
};
use sha2::{Digest, Sha256};

const MAX_CYCLES: u64 = 10_000_000;
const BYTE_SHANNONS: u64 = 100_000_000;
Expand Down Expand Up @@ -342,15 +343,15 @@ fn test_commitment_lock_with_two_pending_htlcs() {
local_delay_epoch.as_u64().to_le_bytes().to_vec(),
blake2b_256(local_delay_epoch_key.1.serialize())[0..20].to_vec(),
blake2b_256(revocation_key.1.serialize())[0..20].to_vec(),
[0u8].to_vec(),
[0b00000000].to_vec(),
payment_amount1.to_le_bytes().to_vec(),
blake2b_256(preimage1)[0..20].to_vec(),
blake2b_256(remote_htlc_key1.1.serialize())[0..20].to_vec(),
blake2b_256(local_htlc_key1.1.serialize())[0..20].to_vec(),
expiry1.as_u64().to_le_bytes().to_vec(),
[1u8].to_vec(),
[0b00000011].to_vec(),
payment_amount2.to_le_bytes().to_vec(),
blake2b_256(preimage2)[0..20].to_vec(),
Sha256::digest(preimage2)[0..20].to_vec(),
blake2b_256(remote_htlc_key2.1.serialize())[0..20].to_vec(),
blake2b_256(local_htlc_key2.1.serialize())[0..20].to_vec(),
expiry2.as_u64().to_le_bytes().to_vec(),
Expand Down Expand Up @@ -479,9 +480,9 @@ fn test_commitment_lock_with_two_pending_htlcs() {
local_delay_epoch.as_u64().to_le_bytes().to_vec(),
blake2b_256(local_delay_epoch_key.1.serialize())[0..20].to_vec(),
blake2b_256(revocation_key.1.serialize())[0..20].to_vec(),
[1u8].to_vec(),
[0b00000011].to_vec(),
payment_amount2.to_le_bytes().to_vec(),
blake2b_256(preimage2)[0..20].to_vec(),
Sha256::digest(preimage2)[0..20].to_vec(),
blake2b_256(remote_htlc_key2.1.serialize())[0..20].to_vec(),
blake2b_256(local_htlc_key2.1.serialize())[0..20].to_vec(),
expiry2.as_u64().to_le_bytes().to_vec(),
Expand Down Expand Up @@ -650,7 +651,7 @@ fn test_commitment_lock_with_two_pending_htlcs() {
local_delay_epoch.as_u64().to_le_bytes().to_vec(),
blake2b_256(local_delay_epoch_key.1.serialize())[0..20].to_vec(),
blake2b_256(revocation_key.1.serialize())[0..20].to_vec(),
[0u8].to_vec(),
[0b00000000].to_vec(),
payment_amount1.to_le_bytes().to_vec(),
blake2b_256(preimage1)[0..20].to_vec(),
blake2b_256(remote_htlc_key1.1.serialize())[0..20].to_vec(),
Expand Down Expand Up @@ -805,13 +806,13 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
local_delay_epoch.as_u64().to_le_bytes().to_vec(),
blake2b_256(local_delay_epoch_key.1.serialize())[0..20].to_vec(),
blake2b_256(revocation_key.1.serialize())[0..20].to_vec(),
[0u8].to_vec(),
[0b00000000].to_vec(),
payment_amount1.to_le_bytes().to_vec(),
blake2b_256(preimage1)[0..20].to_vec(),
blake2b_256(remote_htlc_key1.1.serialize())[0..20].to_vec(),
blake2b_256(local_htlc_key1.1.serialize())[0..20].to_vec(),
expiry1.as_u64().to_le_bytes().to_vec(),
[1u8].to_vec(),
[0b00000001].to_vec(),
payment_amount2.to_le_bytes().to_vec(),
blake2b_256(preimage2)[0..20].to_vec(),
blake2b_256(remote_htlc_key2.1.serialize())[0..20].to_vec(),
Expand Down Expand Up @@ -953,7 +954,7 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
local_delay_epoch.as_u64().to_le_bytes().to_vec(),
blake2b_256(local_delay_epoch_key.1.serialize())[0..20].to_vec(),
blake2b_256(revocation_key.1.serialize())[0..20].to_vec(),
[1u8].to_vec(),
[0b00000001].to_vec(),
payment_amount2.to_le_bytes().to_vec(),
blake2b_256(preimage2)[0..20].to_vec(),
blake2b_256(remote_htlc_key2.1.serialize())[0..20].to_vec(),
Expand Down Expand Up @@ -1065,7 +1066,7 @@ fn test_commitment_lock_with_two_pending_htlcs_and_sudt() {
local_delay_epoch.as_u64().to_le_bytes().to_vec(),
blake2b_256(local_delay_epoch_key.1.serialize())[0..20].to_vec(),
blake2b_256(revocation_key.1.serialize())[0..20].to_vec(),
[0u8].to_vec(),
[0b00000000].to_vec(),
payment_amount1.to_le_bytes().to_vec(),
blake2b_256(preimage1)[0..20].to_vec(),
blake2b_256(remote_htlc_key1.1.serialize())[0..20].to_vec(),
Expand Down
Loading