Skip to content

Commit

Permalink
Merge pull request #6 from quake/quake/payment-hash-type
Browse files Browse the repository at this point in the history
feat: add payment hash type
  • Loading branch information
quake authored Jun 28, 2024
2 parents 21c70cc + 99f871b commit 4d0becb
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 55 deletions.
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

0 comments on commit 4d0becb

Please sign in to comment.