Skip to content
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Unreleased

* Add `Value` and `Type` constructors for variable-length buffers and SHA256 `Ctx8` contexts;
change the signature of `Final::two_two_n` to return a result rather than panicking when `n`
is too large; add infallible `Final::two_two_n_fixed` for when `n` is known at compile-time
[#372][https://github.com/BlockstreamResearch/rust-simplicity/pull/372)

# 0.8.0 - 2026-05-28

* Add runtime jet type check in `Context` [#361](https://github.com/BlockstreamResearch/rust-simplicity/pull/361)
Expand Down
4 changes: 2 additions & 2 deletions jets-bench/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn var_len_buf_from_slice(v: &[u8], n: usize) -> Result<Value, EarlyEndOfStr
let mut iter = BitIter::new(v.iter().copied());
let mut res = None;
for i in (0..n).rev() {
let ty = Final::two_two_n(i + 3);
let ty = Final::two_two_n(i + 3).unwrap();
let v = if v.len() & 1 << i != 0 {
let val = Value::from_compact_bits(&mut iter, &ty)?;
Value::some(val)
Expand Down Expand Up @@ -414,7 +414,7 @@ impl BenchSample for SimplicityPoint {
// Sample genesis pegin with 50% probability
pub fn genesis_pegin() -> Value {
if rand::random() {
Value::none(Final::two_two_n(8))
Value::none(Final::two_two_n_fixed::<8>())
} else {
let genesis_hash = rand::random::<[u8; 32]>();
Value::some(Value::u256(genesis_hash))
Expand Down
12 changes: 6 additions & 6 deletions src/jet/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ impl TypeName {
for c in self.0.iter().rev() {
match c {
b'1' => stack.push(Final::unit()),
b'2' => stack.push(Final::two_two_n(0)),
b'c' => stack.push(Final::two_two_n(3)),
b's' => stack.push(Final::two_two_n(4)),
b'i' => stack.push(Final::two_two_n(5)),
b'l' => stack.push(Final::two_two_n(6)),
b'h' => stack.push(Final::two_two_n(8)),
b'2' => stack.push(Final::two_two_n_fixed::<0>()),
b'c' => stack.push(Final::two_two_n_fixed::<3>()),
b's' => stack.push(Final::two_two_n_fixed::<4>()),
b'i' => stack.push(Final::two_two_n_fixed::<5>()),
b'l' => stack.push(Final::two_two_n_fixed::<6>()),
b'h' => stack.push(Final::two_two_n_fixed::<8>()),
b'+' | b'*' => {
let left = stack.pop().expect("Illegal type name syntax!");
let right = stack.pop().expect("Illegal type name syntax!");
Expand Down
164 changes: 163 additions & 1 deletion src/merkle/tmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,129 @@ impl Tmr {
])),
];

/// The TMRs of the types (TWO^8)^<(2^(N + 1)) for small values of n
#[rustfmt::skip]
pub const BUFFER8_TWO_N_PLUS_ONE: [Tmr; 16] = [
Tmr(Midstate([
0x66, 0x8c, 0x79, 0xa6, 0xf0, 0xe0, 0x86, 0xa6,
0x2d, 0x73, 0xf0, 0xc6, 0x52, 0xb1, 0x5c, 0x56,
0xb1, 0xd3, 0x53, 0x68, 0xe1, 0xff, 0xad, 0x76,
0xc9, 0xd4, 0xdb, 0xae, 0xb5, 0x2d, 0xe6, 0x2f,
])),
Tmr(Midstate([
0x9f, 0x91, 0xf5, 0x19, 0x9b, 0xb8, 0x16, 0x7a,
0x3b, 0x6c, 0xf8, 0xd0, 0x39, 0x75, 0x6e, 0x1b,
0x33, 0x18, 0x42, 0x6e, 0xef, 0x3a, 0x9b, 0xa0,
0x90, 0x2c, 0x91, 0xdc, 0x5f, 0x7e, 0x63, 0x39,
])),
Tmr(Midstate([
0x16, 0x98, 0x45, 0xb0, 0xe2, 0xf0, 0x4a, 0x83,
0x76, 0xfe, 0x91, 0x14, 0xbd, 0x35, 0x3a, 0x29,
0xe9, 0xb7, 0x80, 0x42, 0xb7, 0x70, 0x1b, 0xa1,
0x6d, 0x02, 0xc4, 0x62, 0x18, 0xef, 0x8b, 0xdf,
])),
Tmr(Midstate([
0xbd, 0x59, 0x57, 0x8c, 0x45, 0x78, 0xfe, 0xc4,
0xef, 0x2a, 0x29, 0xc1, 0xad, 0xea, 0x4c, 0xe1,
0x30, 0x6c, 0x1a, 0x2b, 0x10, 0xd6, 0x18, 0xbc,
0x58, 0x44, 0x67, 0x84, 0x17, 0x97, 0x3b, 0x8e,
])),
Tmr(Midstate([
0x88, 0xd1, 0x8c, 0x11, 0x5f, 0x86, 0x54, 0x40,
0x5f, 0xd7, 0x1d, 0xe8, 0x7e, 0x6f, 0xf0, 0x80,
0x6c, 0x5d, 0xa7, 0x97, 0xca, 0xaf, 0x48, 0xe2,
0x47, 0xea, 0xcc, 0x43, 0x99, 0x96, 0x89, 0x1a,
])),
Tmr(Midstate([
0x90, 0x65, 0x22, 0xe1, 0x6d, 0xf3, 0x6f, 0x83,
0xa4, 0x50, 0x32, 0x8a, 0xf8, 0x4e, 0x2f, 0x3e,
0x52, 0xf6, 0xd6, 0x49, 0xa7, 0x88, 0xe3, 0xb2,
0x1c, 0xca, 0xe3, 0xcd, 0x9a, 0x24, 0x66, 0x77,
])),
Tmr(Midstate([
0x3a, 0xba, 0x4c, 0xce, 0x0e, 0x46, 0xc5, 0x54,
0xb4, 0x4f, 0x70, 0x21, 0x3d, 0x4d, 0x8b, 0xd8,
0xe8, 0xf1, 0x7e, 0x2b, 0xd1, 0x7b, 0xdf, 0xb7,
0x15, 0x0a, 0xdf, 0xfd, 0x9a, 0xdf, 0x80, 0x9d,
])),
Tmr(Midstate([
0x7d, 0x81, 0x2a, 0xf0, 0x44, 0xcb, 0x04, 0xd2,
0xaf, 0x4f, 0xc8, 0xe9, 0xb5, 0x30, 0x66, 0x03,
0x9b, 0xd5, 0x89, 0x2a, 0x56, 0xa5, 0xd5, 0x64,
0x1c, 0x5c, 0x58, 0xc8, 0x6e, 0xed, 0x8a, 0x35,
])),
Tmr(Midstate([
0x23, 0x0e, 0xa9, 0x70, 0x03, 0x3e, 0x47, 0xc5,
0x61, 0x68, 0x1e, 0xe7, 0x20, 0x58, 0xb9, 0xc0,
0x75, 0x5b, 0x8d, 0x87, 0x22, 0x80, 0x18, 0x4f,
0x2e, 0x3f, 0xe3, 0x93, 0xc0, 0x47, 0x8f, 0x1a,
])),
Tmr(Midstate([
0x6e, 0x90, 0x88, 0x04, 0x20, 0x46, 0x2b, 0x84,
0xf2, 0x16, 0x30, 0x2a, 0x09, 0x56, 0x9c, 0xc8,
0xd4, 0x47, 0x54, 0x4a, 0xcd, 0x8a, 0xbc, 0x53,
0xd8, 0xa7, 0xcf, 0x21, 0x9b, 0x44, 0x9c, 0x95,
])),
Tmr(Midstate([
0x7a, 0xd1, 0x5d, 0xed, 0x85, 0x02, 0xa6, 0xf1,
0x1e, 0xb8, 0xa4, 0x9b, 0x25, 0xc8, 0xd7, 0x62,
0xa0, 0xfe, 0x00, 0x4f, 0xb5, 0x7d, 0x73, 0x43,
0xbd, 0xf4, 0x90, 0xed, 0x7e, 0xd2, 0xf4, 0x07,
])),
Tmr(Midstate([
0xaa, 0x30, 0x30, 0x15, 0x71, 0xcf, 0x8d, 0x2d,
0x64, 0xe9, 0x65, 0x4b, 0x0c, 0xbd, 0xe0, 0x54,
0x01, 0x77, 0xab, 0xc2, 0xf2, 0xef, 0xfb, 0x7f,
0x05, 0x2e, 0x27, 0xa8, 0xcc, 0xcc, 0xee, 0x62,
])),
Tmr(Midstate([
0x28, 0x6d, 0x4d, 0x57, 0x6d, 0xb8, 0xe8, 0x45,
0x00, 0x9c, 0x74, 0x84, 0xe0, 0x0a, 0x9f, 0xa3,
0xf3, 0x18, 0xa8, 0x21, 0x9e, 0x38, 0x66, 0x2c,
0xda, 0x11, 0x75, 0x78, 0x22, 0xe4, 0x53, 0xbb,
])),
Tmr(Midstate([
0x10, 0x56, 0xa7, 0x17, 0xdc, 0x0c, 0x86, 0xb7,
0x49, 0x97, 0x5e, 0x9c, 0x36, 0x4a, 0xb5, 0xa6,
0x64, 0x77, 0xc4, 0x2d, 0xe1, 0x6e, 0x5b, 0x05,
0x29, 0x81, 0x4f, 0x4c, 0xba, 0x95, 0x7c, 0xb3,
])),
Tmr(Midstate([
0x94, 0x59, 0x0e, 0xf5, 0x66, 0x10, 0xaa, 0x7f,
0xec, 0x46, 0x5b, 0x72, 0x32, 0xab, 0xa3, 0xf4,
0x7c, 0x94, 0x2b, 0x8e, 0x8d, 0xc8, 0x76, 0x82,
0x51, 0xd3, 0x70, 0x2c, 0x99, 0xb9, 0xef, 0xef,
])),
Tmr(Midstate([
0xd0, 0x7f, 0x71, 0xb7, 0xcd, 0x48, 0xb8, 0x50,
0xad, 0x09, 0x06, 0x8b, 0x9b, 0x48, 0xe0, 0xf8,
0x5f, 0x84, 0xc0, 0x1b, 0x34, 0x58, 0x6a, 0x51,
0x34, 0x61, 0xfa, 0xf7, 0x6d, 0x54, 0x34, 0x64,
])),
];

/// The TMR of the `Ctx8` type used by the SHA256 jets.
#[rustfmt::skip]
pub const CTX8: Tmr = Tmr(Midstate([
0x8d, 0x5c, 0xe5, 0xf6, 0xeb, 0xfc, 0x70, 0x61,
0xe7, 0x91, 0x16, 0xbd, 0xf6, 0x6f, 0xb4, 0xe4,
0xc6, 0xca, 0x32, 0xa0, 0x1c, 0xda, 0x48, 0xf6,
0xed, 0xc1, 0x0a, 0xee, 0xfd, 0x31, 0x0e, 0x8c,
]));

/// The TMR for the unit type
pub const fn unit() -> Tmr {
Self::UNIT_IV
}

/// The TMR for the successor of a type.
///
/// Given a type `X`, we define its successor `S X` as `1 + X`.
/// In Rust notation this would be `Option<X>`.
pub fn successor(self) -> Tmr {
Self::SUM_IV.update(Tmr::unit(), self)
}

/// The TMR for the sum of two types, whose TMRs are given
pub fn sum(tmr1: Tmr, tmr2: Tmr) -> Tmr {
Self::SUM_IV.update(tmr1, tmr2)
Expand All @@ -256,8 +374,9 @@ impl Tmr {
mod tests {
use super::*;

use crate::jet::Jet;
use crate::merkle::bip340_iv;
use crate::types;
use crate::types::{self, Final};

#[test]
fn ivs() {
Expand Down Expand Up @@ -317,4 +436,47 @@ mod tests {
}
});
}

#[test]
fn const_buffer8() {
use std::sync::Arc;

let two_8_tmr = Tmr::TWO_TWO_N[3];
let buf_0_tmr = two_8_tmr.successor();

let two_8 = Final::two_two_n_fixed::<3>();
let buf_0 = Arc::clone(&two_8).successor();

assert_eq!(buf_0, Final::buffer8_two_n_plus_one(0).unwrap());
assert_eq!(two_8.tmr(), two_8_tmr);
assert_eq!(buf_0.tmr(), buf_0_tmr);
assert_eq!(buf_0_tmr, Tmr::BUFFER8_TWO_N_PLUS_ONE[0]);

let mut tmr = buf_0_tmr;
let mut fin = buf_0;
assert_eq!(Tmr::BUFFER8_TWO_N_PLUS_ONE.len(), 16);
for n in 1..Tmr::BUFFER8_TWO_N_PLUS_ONE.len() {
tmr = Tmr::product(Tmr::TWO_TWO_N[n + 3].successor(), tmr);
fin = Final::product(Final::two_two_n(n + 3).unwrap().successor(), fin);

assert_eq!(fin.tmr(), tmr);
assert_eq!(fin, Final::buffer8_two_n_plus_one(n).unwrap());
assert_eq!(tmr, Tmr::BUFFER8_TWO_N_PLUS_ONE[n]);

// For the case of n == 5, i.e. a 63-byte buffer (63 = 2^(n + 1) - 1),
// we can check against the SHA256 Ctx8 type to make sure that our
// computations are actually correct.
if n == 5 {
let extra_ctx_stuff = Final::product(
Final::two_two_n_fixed::<6>(), // 2^64
Final::two_two_n_fixed::<8>(), // 2^256
);
let synthetic_ctx_ty = Final::product(Arc::clone(&fin), extra_ctx_stuff);
let actual_ctx_ty = crate::jet::Core::Sha256Ctx8Init.target_ty().to_final();
assert_eq!(synthetic_ctx_ty, actual_ctx_ty,);
assert_eq!(synthetic_ctx_ty, Final::ctx8());
assert_eq!(synthetic_ctx_ty.tmr(), Tmr::CTX8);
}
}
}
}
Loading
Loading