Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
386d0d7
feat(commitments): add ternary mixed-hash integer path
brenorb Sep 11, 2026
59443b5
fix(commitments): enforce ternary integer width
brenorb Sep 18, 2026
89fb32c
test(u4): consolidate word transfer boundaries
brenorb Sep 18, 2026
6b1ac69
test(u4): remove duplicate word transfer metrics
brenorb Sep 18, 2026
d58f309
docs(u32): describe signed compression boundary
brenorb Sep 18, 2026
12245e5
test(u4): document altstack transport boundaries
brenorb Sep 18, 2026
fd74ae2
test(u4): document staged word verification
brenorb Sep 18, 2026
7cab813
test(u4): document lookup table lifecycles
brenorb Sep 18, 2026
328c8be
test(u4): cover out-of-bounds word transfers
brenorb Sep 18, 2026
94c819e
feat(sha1): add midstate continuation
brenorb Sep 11, 2026
a929a0a
feat(ripemd160): add midstate continuation
brenorb Sep 11, 2026
545afc6
feat(ripemd160): add midstate continuation
brenorb Sep 18, 2026
d46cf24
feat(u4): add checked bit-to-nibble packer
brenorb Sep 11, 2026
4cf612b
research(signed-window): measure scalar schedule composition
brenorb Sep 16, 2026
a685a15
research(schnorr): reject radix32 window integration
brenorb Sep 16, 2026
74a77ab
feat(u4): add canonical LSB projection
brenorb Sep 17, 2026
15509a8
feat(u4): add canonical parity projection
brenorb Sep 17, 2026
11dad54
feat(u32): add checked bytewise complement
brenorb Sep 17, 2026
d4af1f3
feat(u32): add checked constant XOR adapter
brenorb Sep 17, 2026
296796f
feat(u4): add presence-bit projection
brenorb Sep 17, 2026
1172171
feat(u4): add fixed-symbol occurrence count
brenorb Sep 17, 2026
a691e8a
docs(blake3): record keyed mode boundary
brenorb Sep 11, 2026
872cba8
Merge origin/main into PR 10: integrate ternary hash path
brenorb Sep 28, 2026
068c6a7
test(commitments): pin ternary width-1/31 rejection to the width check
brenorb Sep 28, 2026
4cf181a
Merge origin/main into PR 10: integrate TapBranch and NR-066 alongsid…
brenorb Sep 28, 2026
3a90cf7
Merge origin/main into PR 136: integrate u4 fixed-symbol count
brenorb Sep 28, 2026
1141c1e
Merge origin/main into PR 132: integrate constant XOR adapter with main
brenorb Sep 28, 2026
5a974ca
Merge origin/main into PR 135: integrate u4 presence-bit projection
brenorb Sep 28, 2026
fa0ae38
Merge origin/main into PR 92: resolve negative-result append conflict
brenorb Sep 28, 2026
ab8950c
Merge origin/main into PR 72: preserve NR entries, rename keyed-mode …
brenorb Sep 28, 2026
13bf557
docs(blake3): renumber keyed-mode open problem to OP-028
brenorb Sep 28, 2026
31c3bab
test(schnorr): check width-8 window table entries against libsecp256k1
brenorb Sep 28, 2026
6d6a9e8
docs(open-problems): make OP-027 the sole signed-window problem
brenorb Sep 28, 2026
e6f59af
Merge origin/main into PR 75: integrate u4 inverse bit packer
brenorb Sep 28, 2026
30a07f1
test(taproot): validate depth-one commitments against Core
adrienlacombe Sep 28, 2026
fc447c1
test(u4): pin exact count stack frontiers
brenorb Sep 28, 2026
5d8b653
test(u4): round-trip the inverse packer over all 16 nibbles
brenorb Sep 28, 2026
23b96ff
test(u4): align presence alias and order tests with the shared contract
brenorb Sep 28, 2026
709cbca
Merge origin/main into PR 71: resolve SHA1 midstate integration confl…
brenorb Sep 28, 2026
e9e6efc
test(u32): align constant XOR adapter tests with sibling contract
brenorb Sep 28, 2026
565e698
Merge origin/main into PR 42: resolve u32 signed-compression conflicts
brenorb Sep 28, 2026
fe52a3b
Merge origin/main into PR 130: integrate checked u32 complement with …
brenorb Sep 28, 2026
70a24c7
Merge origin/main into PR 116: integrate #233 parity tests with canon…
brenorb Sep 28, 2026
9699e28
test(u4): make canonical parity alias tests non-vacuous
brenorb Sep 28, 2026
31d4958
Merge origin/main into PR 113: integrate canonical LSB with range-onl…
brenorb Sep 28, 2026
6fa6631
test(u4): make canonical LSB malformed-input test isolate the canonic…
brenorb Sep 28, 2026
f8e7c15
Merge origin/main into PR 73: resolve ripemd160 midstate conflicts
brenorb Sep 28, 2026
e2e58fa
test(commitments): cover both ternary width-check branches
brenorb Sep 28, 2026
6f006d7
Merge origin/main into PR 49: resolve u4 stack/lookup and metric conf…
brenorb Sep 28, 2026
1e24cb7
Merge remote-tracking branch 'refs/remotes/review/245' into HEAD
Sep 28, 2026
c8a0cf4
Merge remote-tracking branch 'refs/remotes/review/136' into HEAD
Sep 28, 2026
9f9f48c
Merge remote-tracking branch 'refs/remotes/review/135' into HEAD
Sep 28, 2026
fee4693
Merge remote-tracking branch 'refs/remotes/review/132' into HEAD
Sep 28, 2026
f244139
Merge remote-tracking branch 'refs/remotes/review/130' into HEAD
Sep 28, 2026
bef94c1
Merge remote-tracking branch 'refs/remotes/review/116' into HEAD
Sep 28, 2026
b7cadb0
Merge remote-tracking branch 'refs/remotes/review/113' into HEAD
Sep 28, 2026
8dfbd7f
Merge remote-tracking branch 'refs/remotes/review/92' into HEAD
Sep 28, 2026
8cadeec
Merge remote-tracking branch 'refs/remotes/review/75' into HEAD
Sep 28, 2026
937d7e8
Merge remote-tracking branch 'refs/remotes/review/73' into HEAD
Sep 28, 2026
043c3c1
Merge remote-tracking branch 'refs/remotes/review/72' into HEAD
Sep 28, 2026
0fa17f5
Merge remote-tracking branch 'refs/remotes/review/71' into HEAD
Sep 28, 2026
3219a39
Merge remote-tracking branch 'refs/remotes/review/49' into HEAD
Sep 28, 2026
1f13d65
Merge remote-tracking branch 'refs/remotes/review/42' into HEAD
Sep 28, 2026
2cd7a87
Merge remote-tracking branch 'refs/remotes/review/10' into HEAD
Sep 28, 2026
0f796ea
Clean review artifacts and format combined hash metric imports
Sep 28, 2026
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
23 changes: 23 additions & 0 deletions examples/blake3_keyed_boundary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use bitcoin_lab::{
hashes::blake3::blake3_short_compute_script, support::script::ScriptCompilation,
};

fn main() {
let message: Vec<u8> = (0..32).collect();
let key = [0x42u8; 32];
let unkeyed = blake3::hash(&message);
let mut keyed_hasher = blake3::Hasher::new_keyed(&key);
keyed_hasher.update(&message);
let keyed = keyed_hasher.finalize();

assert_ne!(unkeyed, keyed);
println!(
"message_bytes={} key_bytes={} keyed_output_bytes={} current_mode=unkeyed current_compute_script_bytes={}",
message.len(),
key.len(),
keyed.as_bytes().len(),
blake3_short_compute_script(message.len())
.compile_with_policy()
.len()
);
}
189 changes: 188 additions & 1 deletion examples/core_validation_fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,155 @@ fn fixture(
})
}

fn replace_fixture_taproot_context(
row: &mut Value,
script: &ScriptBuf,
witness: &[Vec<u8>],
control: &[u8],
output_script: &ScriptBuf,
) {
let mut complete_witness = witness.to_vec();
complete_witness.push(script.to_bytes());
complete_witness.push(control.to_vec());
row["script_hex"] = json!(script.as_bytes().to_lower_hex_string());
row["script_sha256"] = json!(sha256::Hash::hash(script.as_bytes()).to_string());
row["control_block_hex"] = json!(control.to_lower_hex_string());
row["script_pubkey_hex"] = json!(output_script.as_bytes().to_lower_hex_string());
row["tapleaf_hash"] =
json!(TapLeafHash::from_script(script, LeafVersion::TapScript).to_string());
row["local"] = local_execution(script, witness);
row["local_profiles"] = json!({
"consensus": local_profile(script, witness, TapscriptProfile::Consensus),
"policy": local_profile(script, witness, TapscriptProfile::Policy),
});
row["local_commitment"] = local_commitment(output_script, &complete_witness);
row["metrics"]["locking_script_bytes"] = json!(script.len());
row["metrics"]["taproot_witness_bytes"] =
json!(serialize(&Witness::from_slice(&complete_witness)).len());
row["metrics"]["static_non_push_opcodes"] = json!(0);
}

fn depth_one_commitment_fixtures() -> Vec<Value> {
let secp = Secp256k1::new();
let internal_key = Keypair::from_secret_key(
&secp,
&SecretKey::from_slice(&[0x01; 32]).expect("fixed test key"),
)
.x_only_public_key()
.0;
let script = ScriptBuf::from_bytes(vec![0x51]); // OP_TRUE
let sibling = ScriptBuf::from_bytes(vec![0x00]); // OP_FALSE
let spend_info = TaprootBuilder::new()
.add_leaf(1, script.clone())
.expect("depth-one target leaf")
.add_leaf(1, sibling)
.expect("depth-one sibling leaf")
.finalize(&secp, internal_key)
.expect("complete depth-one tree");
let control = spend_info
.control_block(&(script.clone(), LeafVersion::TapScript))
.expect("depth-one control block")
.serialize();
let output_script = ScriptBuf::new_p2tr_tweaked(spend_info.output_key());
let witness = Vec::<Vec<u8>>::new();

let mut valid = fixture(
"taproot-depth-one-valid",
"A depth-one OP_TRUE leaf with one TapBranch sibling and a valid 65-byte control block.",
script.clone(),
witness.clone(),
RAW_BOUNDARY,
expectations(None, None),
);
replace_fixture_taproot_context(&mut valid, &script, &witness, &control, &output_script);

let mut rows = vec![valid.clone()];
let mut mutation = |name: &str,
description: &str,
revealed_script: ScriptBuf,
mutated_control: Vec<u8>,
rejection: &str| {
let mut row = valid.clone();
row["name"] = json!(name);
row["description"] = json!(description);
row["expected"] = expectations(Some(rejection), None);
row["local_profile_comparison"] = json!({
"scope": "The local commitment preflight rejection gates the combined verdict while preserving the otherwise successful leaf profiles as separate diagnostics",
"compare_to_core": true,
"expected": {"consensus": false, "policy": false},
});
replace_fixture_taproot_context(
&mut row,
&revealed_script,
&witness,
&mutated_control,
&output_script,
);
rows.push(row);
};

let mut parity = control.clone();
parity[0] ^= 1;
mutation(
"taproot-depth-one-parity-flip",
"The output-key parity bit is flipped in an otherwise valid depth-one control block.",
script.clone(),
parity,
"taproot-commitment",
);

let alternate_internal_key = Keypair::from_secret_key(
&secp,
&SecretKey::from_slice(&[0x02; 32]).expect("fixed alternate test key"),
)
.x_only_public_key()
.0
.serialize();
let mut internal_key_mutation = control.clone();
internal_key_mutation[1..33].copy_from_slice(&alternate_internal_key);
mutation(
"taproot-depth-one-internal-key-mutation",
"The control block contains a different valid x-only internal key while retaining the original output and Merkle path.",
script.clone(),
internal_key_mutation,
"taproot-commitment",
);

mutation(
"taproot-depth-one-script-mutation",
"The revealed OP_TRUE leaf is changed to the independently truthy OP_2 bytecode without changing its control block or output.",
ScriptBuf::from_bytes(vec![0x52]),
control.clone(),
"taproot-commitment",
);

let mut sibling_mutation = control.clone();
sibling_mutation[33] ^= 1;
mutation(
"taproot-depth-one-sibling-mutation",
"One bit of the depth-one TapBranch sibling hash is flipped.",
script.clone(),
sibling_mutation,
"taproot-commitment",
);

mutation(
"taproot-depth-one-control-32-bytes",
"The control block is truncated to 32 bytes, below the 33-byte minimum.",
script.clone(),
control[..32].to_vec(),
"taproot-control-size",
);
mutation(
"taproot-depth-one-control-34-bytes",
"The control block is truncated to 34 bytes, which is not 33 plus a whole 32-byte Merkle node.",
script,
control[..34].to_vec(),
"taproot-control-size",
);
rows
}

fn drop_items(count: usize) -> Vec<u8> {
let mut bytes = vec![0x6d; count / 2]; // OP_2DROP
if count % 2 != 0 {
Expand Down Expand Up @@ -627,6 +776,8 @@ fn fixtures() -> Value {
));
}

fixtures.extend(depth_one_commitment_fixtures());

json!({
"schema_version": 2,
"expected_bitcoin_core_version": CORE_VERSION,
Expand Down Expand Up @@ -681,7 +832,7 @@ mod tests {
assert_eq!(first, fixtures());
let rows = first["fixtures"].as_array().unwrap();
assert_eq!(first["fixture_count"], rows.len());
assert_eq!(rows.len(), 46);
assert_eq!(rows.len(), 53);
let interpreter = provenance::interpreter().unwrap();
assert_eq!(first["local_interpreter"]["name"], interpreter.name);
assert_eq!(first["local_interpreter"]["commit"], interpreter.commit);
Expand Down Expand Up @@ -773,6 +924,42 @@ mod tests {
invalid_control["local_profiles"]["consensus"]["accepted"],
true
);
let depth_one = rows
.iter()
.filter(|row| {
row["name"]
.as_str()
.is_some_and(|name| name.starts_with("taproot-depth-one-"))
})
.collect::<Vec<_>>();
assert_eq!(depth_one.len(), 7);
let depth_one_valid = depth_one
.iter()
.find(|row| row["name"] == "taproot-depth-one-valid")
.unwrap();
assert_eq!(
depth_one_valid["control_block_hex"].as_str().unwrap().len(),
130
);
assert_eq!(depth_one_valid["metrics"]["locking_script_bytes"], 1);
assert_eq!(depth_one_valid["metrics"]["data_witness_bytes"], 1);
assert_eq!(depth_one_valid["metrics"]["taproot_witness_bytes"], 69);
assert_eq!(depth_one_valid["local_commitment"]["accepted"], true);
assert_eq!(
depth_one_valid["local_profiles"]["consensus"]["accepted"],
true
);
for row in depth_one {
assert_eq!(row["local_profiles"]["consensus"]["accepted"], true);
assert_eq!(row["local_profiles"]["policy"]["accepted"], true);
if row["name"] == "taproot-depth-one-valid" {
assert_eq!(row["local_commitment"]["outcome"], "valid");
} else {
assert_eq!(row["local_commitment"]["outcome"], "invalid");
assert_eq!(row["expected"]["consensus"], false);
assert_eq!(row["expected"]["policy"], false);
}
}
let names: std::collections::HashSet<_> = rows.iter().map(|row| &row["name"]).collect();
assert_eq!(names.len(), rows.len());
for row in rows {
Expand Down
Loading
Loading