Skip to content
Open
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: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const BINARIES: &[(&str, &str)] = &[
),
(
"secp256k1_blake160_multisig_all",
"36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29",
"fcc633b5dae45217eaea21f3283c5433683bc556a668c327a1f7f003edaafe63",
),
];

Expand Down
6 changes: 4 additions & 2 deletions c/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ Defines commonly used high level functions and constants.
/* since */
#define SINCE_VALUE_BITS 56
#define SINCE_VALUE_MASK 0x00ffffffffffffff
#define SINCE_EPOCH_FRACTION_FLAG 0b00100000
#define SINCE_EPOCH_FRACTION_ABSOLUTE_FLAG 0b00100000
#define SINCE_EPOCH_FRACTION_RELATIVE_FLAG 0b10100000

/* calculate inputs length */
int calculate_inputs_len() {
Expand Down Expand Up @@ -111,7 +112,8 @@ int check_since(uint64_t since) {
if (since_flags != input_since_flags) {
return ERROR_INCORRECT_SINCE_FLAGS;
}
if (input_since_flags == SINCE_EPOCH_FRACTION_FLAG) {
if (input_since_flags == SINCE_EPOCH_FRACTION_ABSOLUTE_FLAG ||
input_since_flags == SINCE_EPOCH_FRACTION_RELATIVE_FLAG) {
ret = epoch_number_with_fraction_cmp(input_since_value, since_value);
if (ret < 0) {
return ERROR_INCORRECT_SINCE_VALUE;
Expand Down
8 changes: 8 additions & 0 deletions c/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,19 @@ int epoch_number_with_fraction_cmp(uint64_t a, uint64_t b) {
uint64_t a_epoch = (a >> NUMBER_OFFSET) & NUMBER_MASK;
uint64_t a_index = (a >> INDEX_OFFSET) & INDEX_MASK;
uint64_t a_len = (a >> LENGTH_OFFSET) & LENGTH_MASK;
if (a_len == 0) {
a_index = 0;
a_len = 1;
}

/* extract b epoch */
uint64_t b_epoch = (b >> NUMBER_OFFSET) & NUMBER_MASK;
uint64_t b_index = (b >> INDEX_OFFSET) & INDEX_MASK;
uint64_t b_len = (b >> LENGTH_OFFSET) & LENGTH_MASK;
if (b_len == 0) {
b_index = 0;
b_len = 1;
}

if (a_epoch < b_epoch) {
return -1;
Expand Down
250 changes: 250 additions & 0 deletions src/tests/secp256k1_blake160_multisig_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,256 @@ fn test_multisig_0_2_3_unlock_with_since_epoch() {
}
}

#[test]
fn test_multisig_0_2_3_unlock_with_since_relative_epoch() {
let mut data_loader = DummyDataLoader::new();
let keys = generate_keys(3);
let since_epoch = EpochNumberWithFraction::new(200, 5, 100);
// relative epoch flag: 0b10100000 << 56
let since = 0xa000_0000_0000_0000u64 + since_epoch.full_value();
let multi_sign_script = gen_multi_sign_script(&keys, 2, 0);
let args = {
let mut buf = blake160(&multi_sign_script).to_vec();
buf.extend(since.to_le_bytes().iter());
Bytes::from(buf)
};
let lock_script = gen_multi_sign_lock_script(args.clone());
let raw_tx = gen_tx(&mut data_loader, args);
{
// default since is 0, flags mismatch
let tx = multi_sign_tx(raw_tx.clone(), &multi_sign_script, &[&keys[0], &keys[1]]);
let verify_result = verify(&data_loader, &tx);
assert_error_eq!(
verify_result.unwrap_err(),
ScriptError::validation_failure(&lock_script, ERROR_INCORRECT_SINCE_FLAG)
.input_lock_script(0),
);
}
{
// absolute epoch flag instead of relative
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0x2000_0000_0000_0000u64 + since_epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
let verify_result = verify(&data_loader, &tx);
assert_error_eq!(
verify_result.unwrap_err(),
ScriptError::validation_failure(&lock_script, ERROR_INCORRECT_SINCE_FLAG)
.input_lock_script(0),
);
}
{
// smaller fraction: 200 + 2/200 < 200 + 5/100
let epoch = EpochNumberWithFraction::new(200, 2, 200);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0xa000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
let verify_result = verify(&data_loader, &tx);
assert_error_eq!(
verify_result.unwrap_err(),
ScriptError::validation_failure(&lock_script, ERROR_INCORRECT_SINCE_VALUE)
.input_lock_script(0),
);
}
{
// smaller fraction: 200 + 1/600 < 200 + 5/100
let epoch = EpochNumberWithFraction::new(200, 1, 600);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0xa000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
let verify_result = verify(&data_loader, &tx);
assert_error_eq!(
verify_result.unwrap_err(),
ScriptError::validation_failure(&lock_script, ERROR_INCORRECT_SINCE_VALUE)
.input_lock_script(0),
);
}
{
// larger fraction with different encoding: 200 + 6/50 > 200 + 5/100
let epoch = EpochNumberWithFraction::new(200, 6, 50);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0xa000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}
{
// larger fraction: 200 + 1/2 > 200 + 5/100
// packed integer is smaller (length in high bits), so integer compare would wrongly fail
let epoch = EpochNumberWithFraction::new(200, 1, 2);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0xa000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}
{
let epoch = EpochNumberWithFraction::new(200, 6, 100);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0xa000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}
{
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| i.as_builder().since(since.pack()).build())
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}
{
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| i.as_builder().since((since + 1).pack()).build())
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}
}

#[test]
fn test_multisig_0_2_3_unlock_with_since_epoch_length_zero() {
let mut data_loader = DummyDataLoader::new();
let keys = generate_keys(3);
let since_epoch = EpochNumberWithFraction::new(200, 5, 100);
let since = 0x2000_0000_0000_0000u64 + since_epoch.full_value();
let multi_sign_script = gen_multi_sign_script(&keys, 2, 0);
let args = {
let mut buf = blake160(&multi_sign_script).to_vec();
buf.extend(since.to_le_bytes().iter());
Bytes::from(buf)
};
let lock_script = gen_multi_sign_lock_script(args.clone());
let raw_tx = gen_tx(&mut data_loader, args);

{
let input_since = 0x2000_0000_0000_0000u64 | (100u64 << 24) | 200u64;
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| i.as_builder().since(input_since.pack()).build())
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
let verify_result = verify(&data_loader, &tx);
assert_error_eq!(
verify_result.unwrap_err(),
ScriptError::validation_failure(&lock_script, ERROR_INCORRECT_SINCE_VALUE)
.input_lock_script(0),
);
}

{
let input_since = 0x2000_0000_0000_0000u64 | 201u64;
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| i.as_builder().since(input_since.pack()).build())
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}

{
let epoch = EpochNumberWithFraction::new(200, 4, 100);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0x2000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
let verify_result = verify(&data_loader, &tx);
assert_error_eq!(
verify_result.unwrap_err(),
ScriptError::validation_failure(&lock_script, ERROR_INCORRECT_SINCE_VALUE)
.input_lock_script(0),
);
}

{
let epoch = EpochNumberWithFraction::new(200, 6, 100);
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| {
i.as_builder()
.since((0x2000_0000_0000_0000u64 + epoch.full_value()).pack())
.build()
})
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}

{
let inputs: Vec<CellInput> = raw_tx
.inputs()
.into_iter()
.map(|i| i.as_builder().since(since.pack()).build())
.collect();
let raw_tx = raw_tx.as_advanced_builder().set_inputs(inputs).build();
let tx = multi_sign_tx(raw_tx, &multi_sign_script, &[&keys[1], &keys[2]]);
verify(&data_loader, &tx).expect("pass verification");
}
}

#[test]
fn test_genesis_time_locked_cell() {
// Test against ckb1qyqxs3hhwx2ttqcrk2yk2nsgqteglvfjt4hsjpzgxs,5200,2020-02-09
Expand Down
Loading