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
70 changes: 70 additions & 0 deletions src/jet/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! Source and target types of jet nodes need to be specified manually.

use crate::types::{self, Final, Type};
use crate::Tmr;
use std::cmp;
use std::sync::Arc;

Expand All @@ -30,6 +31,18 @@ use std::sync::Arc;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct TypeName(pub &'static [u8]);

impl PartialEq<Final> for TypeName {
fn eq(&self, other: &Final) -> bool {
self.tmr() == other.tmr()
}
}

impl PartialEq<TypeName> for Final {
fn eq(&self, other: &TypeName) -> bool {
self.tmr() == other.tmr()
}
}

impl TypeName {
/// Convert the type name into a type.
pub fn to_type<'brand>(&self, ctx: &types::Context<'brand>) -> Type<'brand> {
Expand Down Expand Up @@ -70,6 +83,40 @@ impl TypeName {
}
}

/// Compute the TMR of the type name.
pub fn tmr(&self) -> Tmr {
let mut stack = Vec::with_capacity(16);

for c in self.0.iter().rev() {
match c {
b'1' => stack.push(Tmr::unit()),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These repeated mappings might be a source of errors in future. Not how to clean it up though.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Rust is really bad at expressing abstract algorithms. Not much we can do.

b'2' => stack.push(Tmr::TWO_TWO_N[0]),
b'c' => stack.push(Tmr::TWO_TWO_N[3]),
b's' => stack.push(Tmr::TWO_TWO_N[4]),
b'i' => stack.push(Tmr::TWO_TWO_N[5]),
b'l' => stack.push(Tmr::TWO_TWO_N[6]),
b'h' => stack.push(Tmr::TWO_TWO_N[8]),
b'+' | b'*' => {
let left = stack.pop().expect("Illegal type name syntax!");
let right = stack.pop().expect("Illegal type name syntax!");

match c {
b'+' => stack.push(Tmr::sum(left, right)),
b'*' => stack.push(Tmr::product(left, right)),
_ => unreachable!(),
}
}
_ => panic!("Illegal type name syntax!"),
}
}

if stack.len() == 1 {
stack.pop().unwrap()
} else {
panic!("Illegal type name syntax!")
}
}

/// Convert the type name into a type's bitwidth.
///
/// This is more efficient than creating the type and computing its bit-width
Expand Down Expand Up @@ -106,3 +153,26 @@ impl TypeName {
}
}
}

#[cfg(test)]
mod tests {
use crate::jet::{Core, Jet};

#[test]
fn all_jet_tmrs() {
for jet in &Core::ALL {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core is probably sufficient, but there may be some types in Elements that are not in Core.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered that, but then I'd have to feature-gate the test and it seemed like the effort was not worth the additional coverage.

let source_final = jet.source_ty().to_final();
let target_final = jet.target_ty().to_final();

assert_eq!(*source_final, jet.source_ty());
assert_eq!(jet.source_ty(), *source_final);
assert_eq!(source_final.tmr(), jet.source_ty().tmr());
assert_eq!(source_final.bit_width(), jet.source_ty().to_bit_width());

assert_eq!(*target_final, jet.target_ty());
assert_eq!(jet.target_ty(), *target_final);
assert_eq!(target_final.tmr(), jet.target_ty().tmr());
assert_eq!(target_final.bit_width(), jet.target_ty().to_bit_width());
}
}
}
12 changes: 6 additions & 6 deletions src/merkle/cmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ impl From<Tmr> for Cmr {

impl Cmr {
/// Produce a CMR for an iden combinator
pub fn iden() -> Self {
Self::IDEN_IV.into_merkle_root()
pub const fn iden() -> Self {
Self::from_byte_array(Self::IDEN_IV.to_parts().0)
}

/// Produce a CMR for a unit combinator
pub fn unit() -> Self {
Self::UNIT_IV.into_merkle_root()
pub const fn unit() -> Self {
Self::from_byte_array(Self::UNIT_IV.to_parts().0)
}

/// Produce a CMR for an injl combinator
Expand Down Expand Up @@ -84,8 +84,8 @@ impl Cmr {
}

/// Produce a CMR for a witness combinator
pub fn witness() -> Self {
Self::WITNESS_IV.into_merkle_root()
pub const fn witness() -> Self {
Self::from_byte_array(Self::WITNESS_IV.to_parts().0)
}

/// Produce a CMR for a fail combinator
Expand Down
8 changes: 4 additions & 4 deletions src/merkle/ihr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ impl From<Tmr> for Ihr {

impl Imr {
/// Produce a CMR for an iden combinator
pub fn iden() -> Self {
Self::IDEN_IV.into_merkle_root()
pub const fn iden() -> Self {
Self::from_byte_array(Self::IDEN_IV.to_parts().0)
}

/// Produce a CMR for a unit combinator
pub fn unit() -> Self {
Self::UNIT_IV.into_merkle_root()
pub const fn unit() -> Self {
Self::from_byte_array(Self::UNIT_IV.to_parts().0)
}

/// Produce a CMR for an injl combinator
Expand Down
15 changes: 10 additions & 5 deletions src/merkle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ impl FailEntropy {
pub const ZERO: Self = FailEntropy([0; 64]);

/// Construct a [`FailEntropy`] from raw data
pub fn from_byte_array(data: [u8; 64]) -> Self {
pub const fn from_byte_array(data: [u8; 64]) -> Self {
FailEntropy(data)
}

/// Extract the raw bytes from a [`FailEntropy`].
pub fn to_byte_array(self) -> [u8; 64] {
pub const fn to_byte_array(self) -> [u8; 64] {
self.0
}
}
Expand Down Expand Up @@ -101,7 +101,7 @@ fn compact_value(value: &Value) -> [u8; 32] {
.0
}

fn bip340_iv(tag: &[u8]) -> sha256::Midstate {
const fn bip340_iv(tag: &[u8]) -> sha256::Midstate {
sha256::Midstate::hash_tag(tag)
}

Expand Down Expand Up @@ -146,14 +146,19 @@ macro_rules! impl_mr_type {

impl $wrapper {
/// Converts the given tagged hash into a byte array
pub fn from_byte_array(data: [u8; 32]) -> Self {
pub const fn from_byte_array(data: [u8; 32]) -> Self {
$wrapper(data)
}

/// Converts the given tagged hash into a byte array
pub fn to_byte_array(self) -> [u8; 32] {
pub const fn to_byte_array(self) -> [u8; 32] {
self.0
}

/// Converts the given tagged hash into a byte array
pub const fn as_byte_array(&self) -> &[u8; 32] {
&self.0
}
}

impl_serde_string!($wrapper);
Expand Down
4 changes: 2 additions & 2 deletions src/merkle/tmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ impl Tmr {
]);

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

/// The TMR for the successor of a type.
Expand Down
2 changes: 1 addition & 1 deletion src/types/arrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ impl<'brand> CoreConstructible<'brand> for Arrow<'brand> {
fn const_word(inference_context: &Context<'brand>, word: Word) -> Self {
Arrow {
source: Type::unit(inference_context),
target: Type::two_two_n(inference_context, word.n() as usize), // cast safety: 32-bit machine or higher
target: Type::two_two_n(inference_context, word.n()),
inference_context: inference_context.shallow_clone(),
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/types/final_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,8 @@ impl Final {
/// ## Post condition
///
/// 0 ≤ n < 32.
pub fn as_word(&self) -> Option<u32> {
(0..32u32).find(|&n| {
self.tmr == Tmr::TWO_TWO_N[n as usize] // cast safety: 32-bit machine or higher
})
pub fn as_word(&self) -> Option<u8> {
(0u8..32).find(|&n| self.tmr == Tmr::TWO_TWO_N[usize::from(n)])
}

/// Compute the padding of left values of the sum type `Self + Other`.
Expand Down
60 changes: 52 additions & 8 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

use crate::dag::{Dag, DagLike};
use crate::types::{CompleteBound, Final};
use crate::{BitCollector, EarlyEndOfStreamError};
use crate::{BitIter, Tmr};

use crate::{BitCollector, EarlyEndOfStreamError};
use hashes::sha256;

use core::{cmp, fmt, iter};
use std::collections::VecDeque;
use std::hash::Hash;
Expand Down Expand Up @@ -497,6 +499,48 @@ impl Value {
})
}

/// Constructs a `Ctx8` from raw parts.
///
/// Bear in mind that the count is a count of **bytes**, not a count of **bits**. For the
/// context to be valid (i.e. something that could be obtained by a sequence of hashing
/// operations), `bytes_hashed % 64` must equal `buffer.len()`.
///
/// You may want to obtain a hash engine and call [`Self::ctx8_from_hash_engine`] instead.
///
/// # Errors
///
/// Errors if the `buffer` exceeds the maximum length of a sha256 buffer (63 bytes).
pub fn ctx8(
midstate: [u8; 32],
bytes_hashed: u64,
buffer: &[u8],
) -> Result<Self, Buffer8Error> {
Ok(Self::product(
Self::buffer8_two_n_plus_one(5, buffer)?,
Self::product(Self::u64(bytes_hashed), Self::u256(midstate)),
))
}

/// Converts a SHA256 midstate into a Simplicity value.
pub fn ctx8_from_midstate(midstate: sha256::Midstate) -> Self {
let (hash, n) = midstate.to_parts();
Self::ctx8(hash, n, &[]).expect("0 < 64")
}

/// Converts a SHA256 engine into a Simplicity value.
pub fn ctx8_from_hash_engine(engine: &sha256::HashEngine) -> Self {
match engine.midstate() {
Ok(midstate) => {
let (hash, n) = midstate.to_parts();
Self::ctx8(hash, n, &[]).expect("0 < 64")
}
Err(midstate_err) => {
let (hash, n) = midstate_err.midstate().to_parts();
Self::ctx8(hash, n, midstate_err.unprocessed_bytes()).expect("< 64")
}
}
}

/// Return the bit length of the value in compact encoding.
pub fn compact_len(&self) -> usize {
self.iter_compact().count()
Expand Down Expand Up @@ -1012,7 +1056,7 @@ pub struct Word {
/// Value of type `TWO^(2^n)`.
value: Value,
/// 0 ≤ n < 32.
n: u32,
n: u8,
}

macro_rules! construct_word_fallible {
Expand Down Expand Up @@ -1091,16 +1135,16 @@ impl Word {
}

/// The word is of type `TWO^(2^n)`. Return `n`.
pub fn n(&self) -> u32 {
self.n
pub fn n(&self) -> usize {
usize::from(self.n)
}

/// Return the bit length of the word.
///
/// The word is of type `TWO^(2^n)`. Return `2^n`.
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
2usize.pow(self.n)
2usize.pow(u32::from(self.n))
}

/// Return an iterator over the bit encoding of the word.
Expand All @@ -1120,12 +1164,12 @@ impl Word {
bits: &mut BitIter<I>,
n: u32,
) -> Result<Self, EarlyEndOfStreamError> {
let nsize = usize::try_from(n).unwrap_or(usize::MAX); // usize::MAX will error on next line
let Ok(ty) = Final::two_two_n(nsize) else {
let n8 = u8::try_from(n).unwrap_or(u8::MAX); // u8::MAX will error on next line
let Ok(ty) = Final::two_two_n(usize::from(n8)) else {
panic!("TWO^(2^{n}) is not supported as a word type");
};
let value = Value::from_compact_bits(bits, &ty)?;
Ok(Self { value, n })
Ok(Self { value, n: n8 })
}
}

Expand Down
Loading