From 6fd9b886f3001ae87ee5e1921d54ec41f2d882ee Mon Sep 17 00:00:00 2001 From: ivanlele Date: Wed, 27 May 2026 12:24:48 +0300 Subject: [PATCH] Implement Core JetHinter --- codegen/src/main.rs | 10 +- src/ast.rs | 55 ++- src/jet/core.rs | 815 ++++++++++++++++++++++++++++++++ src/{jet.rs => jet/elements.rs} | 163 +------ src/jet/mod.rs | 157 ++++++ src/lib.rs | 50 +- src/tracker.rs | 6 +- 7 files changed, 1065 insertions(+), 191 deletions(-) create mode 100644 src/jet/core.rs rename src/{jet.rs => jet/elements.rs} (91%) create mode 100644 src/jet/mod.rs diff --git a/codegen/src/main.rs b/codegen/src/main.rs index f6ae3406..926a8e5a 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -35,7 +35,7 @@ fn write_jet(jet: Elements, w: &mut W) -> io::Result<()> { writeln!(w, "///")?; writeln!(w, "/// {} mWU _(milli weight units)_", jet.cost())?; write!(w, "pub fn {jet}(")?; - let parameters = simplicityhl::jet::source_type(jet); + let parameters = simplicityhl::jet::source_type(&jet); for (i, ty) in parameters.iter().enumerate() { let identifier = (b'a' + i as u8) as char; if i == parameters.len() - 1 { @@ -44,10 +44,10 @@ fn write_jet(jet: Elements, w: &mut W) -> io::Result<()> { write!(w, "{identifier}: {ty}, ")?; } } - let target = simplicityhl::jet::target_type(jet); + let target = simplicityhl::jet::target_type(&jet); match target.is_unit() { true => writeln!(w, ") {{")?, - false => writeln!(w, ") -> {} {{", simplicityhl::jet::target_type(jet))?, + false => writeln!(w, ") -> {} {{", simplicityhl::jet::target_type(&jet))?, } writeln!(w, " todo!()")?; @@ -104,12 +104,12 @@ fn generate_docs(output_path: PathBuf) -> Result<(), Box> haskell_name: format!("{:?}", jet), simplicityhl_name: jet.to_string(), section: section_name.clone(), - input_type: simplicityhl::jet::source_type(jet) + input_type: simplicityhl::jet::source_type(&jet) .iter() .map(|ty| ty.to_string()) .collect::>() .join(", "), - output_type: simplicityhl::jet::target_type(jet).to_string(), + output_type: simplicityhl::jet::target_type(&jet).to_string(), description: jet.documentation().to_string(), deprecated: jet.is_deprecated(), }) diff --git a/src/ast.rs b/src/ast.rs index fca0947f..6ca2aa1b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -5,12 +5,12 @@ use std::sync::Arc; use either::Either; use miniscript::iter::{Tree, TreeLike}; -use simplicity::jet::{Elements, Jet}; +use simplicity::jet::{Core, Elements, Jet}; use crate::debug::{CallTracker, DebugSymbols, TrackedCallName}; use crate::driver::{FileScoped, SymbolTable, MAIN_MODULE, MAIN_STR}; use crate::error::{Error, RichError, Span, WithSpan}; -use crate::jet::JetHL; +use crate::jet::{source_type, target_type, JetHL}; use crate::num::{NonZeroPow2Usize, Pow2Usize}; use crate::parse::MatchPattern; use crate::pattern::Pattern; @@ -557,31 +557,38 @@ pub trait JetHinter: std::fmt::Debug + Send + Sync { fn clone_box(&self) -> Box; } -#[derive(Clone, Debug, Default)] -pub struct ElementsJetHinter; +macro_rules! impl_jet_hinter { + ($struct_name:ident, $jet_type:ident) => { + #[derive(Clone, Debug, Default)] + pub struct $struct_name; -impl ElementsJetHinter { - pub fn new() -> Self { - Self - } -} + impl $struct_name { + pub fn new() -> Self { + Self + } + } -impl JetHinter for ElementsJetHinter { - fn parse_jet(&self, name: &str) -> Option> { - Elements::parse(name) - .ok() - .map(|jet| -> Box { Box::new(jet) }) - } + impl JetHinter for $struct_name { + fn parse_jet(&self, name: &str) -> Option> { + $jet_type::parse(name) + .ok() + .map(|jet| -> Box { Box::new(jet) }) + } - fn construct_verify(&self) -> Box { - Box::new(Elements::Verify) - } + fn construct_verify(&self) -> Box { + Box::new($jet_type::Verify) + } - fn clone_box(&self) -> Box { - Box::new(Self) - } + fn clone_box(&self) -> Box { + Box::new(Self) + } + } + }; } +impl_jet_hinter!(ElementsJetHinter, Elements); +impl_jet_hinter!(CoreJetHinter, Core); + /// Scope for generating the abstract syntax tree. /// /// The scope is used for: @@ -1356,16 +1363,14 @@ impl AbstractSyntaxTree for Call { let name = CallName::analyze(from, ty, scope)?; let args = match name.clone() { CallName::Jet(jet) => { - let args_tys = jet - .source_type() + let args_tys = source_type(&*jet) .iter() .map(AliasedType::resolve_builtin) .collect::, AliasName>>() .map_err(|alias| Error::UndefinedAlias { name: alias }) .with_span(from)?; check_argument_types(from.args(), &args_tys).with_span(from)?; - let out_ty = jet - .target_type() + let out_ty = target_type(&*jet) .resolve_builtin() .map_err(|alias| Error::UndefinedAlias { name: alias }) .with_span(from)?; diff --git a/src/jet/core.rs b/src/jet/core.rs new file mode 100644 index 00000000..43fa7625 --- /dev/null +++ b/src/jet/core.rs @@ -0,0 +1,815 @@ +use crate::jet::JetHL; +use crate::types::BuiltinAlias::*; +use crate::types::UIntType::*; + +use super::*; + +use simplicity::jet::{Core, Jet}; + +impl JetHL for Core { + fn source_jet_classification(&self) -> SourceJetClassification { + source_jet_classification(*self) + } + + fn target_jet_classification(&self) -> TargetJetClassification { + target_jet_classification(*self) + } + + fn is_disabled(&self) -> bool { + matches!(self, Core::CheckSigVerify | Core::Verify) + } + + fn clone_box(&self) -> Box { + Box::new(*self) + } + + fn as_jet(&self) -> &dyn Jet { + self + } +} + +fn source_jet_classification(jet: Core) -> SourceJetClassification { + match jet { + /* + * ============================== + * Core jets + * ============================== + * + * Multi-bit logic + */ + Core::Low1 + | Core::Low8 + | Core::Low16 + | Core::Low32 + | Core::Low64 + | Core::High1 + | Core::High8 + | Core::High16 + | Core::High32 + | Core::High64 => SourceJetClassification::Unary, + Core::Verify => SourceJetClassification::Custom(vec![bool()]), + Core::Complement1 + | Core::Some1 + | Core::LeftPadLow1_8 + | Core::LeftPadLow1_16 + | Core::LeftPadLow1_32 + | Core::LeftPadLow1_64 + | Core::LeftPadHigh1_8 + | Core::LeftPadHigh1_16 + | Core::LeftPadHigh1_32 + | Core::LeftPadHigh1_64 + | Core::LeftExtend1_8 + | Core::LeftExtend1_16 + | Core::LeftExtend1_32 + | Core::LeftExtend1_64 + | Core::RightPadLow1_8 + | Core::RightPadLow1_16 + | Core::RightPadLow1_32 + | Core::RightPadLow1_64 + | Core::RightPadHigh1_8 + | Core::RightPadHigh1_16 + | Core::RightPadHigh1_32 + | Core::RightPadHigh1_64 => SourceJetClassification::Unary, + Core::Complement8 + | Core::Some8 + | Core::All8 + | Core::Leftmost8_1 + | Core::Leftmost8_2 + | Core::Leftmost8_4 + | Core::Rightmost8_1 + | Core::Rightmost8_2 + | Core::Rightmost8_4 + | Core::LeftPadLow8_16 + | Core::LeftPadLow8_32 + | Core::LeftPadLow8_64 + | Core::LeftPadHigh8_16 + | Core::LeftPadHigh8_32 + | Core::LeftPadHigh8_64 + | Core::LeftExtend8_16 + | Core::LeftExtend8_32 + | Core::LeftExtend8_64 + | Core::RightPadLow8_16 + | Core::RightPadLow8_32 + | Core::RightPadLow8_64 + | Core::RightPadHigh8_16 + | Core::RightPadHigh8_32 + | Core::RightPadHigh8_64 + | Core::RightExtend8_16 + | Core::RightExtend8_32 + | Core::RightExtend8_64 => SourceJetClassification::Unary, + Core::Complement16 + | Core::Some16 + | Core::All16 + | Core::Leftmost16_1 + | Core::Leftmost16_2 + | Core::Leftmost16_4 + | Core::Leftmost16_8 + | Core::Rightmost16_1 + | Core::Rightmost16_2 + | Core::Rightmost16_4 + | Core::Rightmost16_8 + | Core::LeftPadLow16_32 + | Core::LeftPadLow16_64 + | Core::LeftPadHigh16_32 + | Core::LeftPadHigh16_64 + | Core::LeftExtend16_32 + | Core::LeftExtend16_64 + | Core::RightPadLow16_32 + | Core::RightPadLow16_64 + | Core::RightPadHigh16_32 + | Core::RightPadHigh16_64 + | Core::RightExtend16_32 + | Core::RightExtend16_64 => SourceJetClassification::Unary, + Core::Complement32 + | Core::Some32 + | Core::All32 + | Core::Leftmost32_1 + | Core::Leftmost32_2 + | Core::Leftmost32_4 + | Core::Leftmost32_8 + | Core::Leftmost32_16 + | Core::Rightmost32_1 + | Core::Rightmost32_2 + | Core::Rightmost32_4 + | Core::Rightmost32_8 + | Core::Rightmost32_16 + | Core::LeftPadLow32_64 + | Core::LeftPadHigh32_64 + | Core::LeftExtend32_64 + | Core::RightPadLow32_64 + | Core::RightPadHigh32_64 + | Core::RightExtend32_64 => SourceJetClassification::Unary, + Core::Complement64 + | Core::Some64 + | Core::All64 + | Core::Leftmost64_1 + | Core::Leftmost64_2 + | Core::Leftmost64_4 + | Core::Leftmost64_8 + | Core::Leftmost64_16 + | Core::Leftmost64_32 + | Core::Rightmost64_1 + | Core::Rightmost64_2 + | Core::Rightmost64_4 + | Core::Rightmost64_8 + | Core::Rightmost64_16 + | Core::Rightmost64_32 => SourceJetClassification::Unary, + Core::And1 | Core::Or1 | Core::Xor1 | Core::Eq1 => SourceJetClassification::Binary, + Core::And8 | Core::Or8 | Core::Xor8 | Core::Eq8 => SourceJetClassification::Binary, + Core::And16 | Core::Or16 | Core::Xor16 | Core::Eq16 => SourceJetClassification::Binary, + Core::And32 | Core::Or32 | Core::Xor32 | Core::Eq32 => SourceJetClassification::Binary, + Core::And64 | Core::Or64 | Core::Xor64 | Core::Eq64 => SourceJetClassification::Binary, + Core::Eq256 => SourceJetClassification::Binary, + Core::Maj1 | Core::XorXor1 | Core::Ch1 => SourceJetClassification::Ternary, + Core::Maj8 | Core::XorXor8 | Core::Ch8 => SourceJetClassification::Ternary, + Core::Maj16 | Core::XorXor16 | Core::Ch16 => { + SourceJetClassification::Custom(vec![U16.into(), tuple([U16, U16])]) + } + Core::Maj32 | Core::XorXor32 | Core::Ch32 => { + SourceJetClassification::Custom(vec![U32.into(), tuple([U32, U32])]) + } + Core::Maj64 | Core::XorXor64 | Core::Ch64 => { + SourceJetClassification::Custom(vec![U64.into(), tuple([U64, U64])]) + } + Core::FullLeftShift8_1 => SourceJetClassification::Custom(vec![U8.into(), U1.into()]), + Core::FullLeftShift8_2 => SourceJetClassification::Custom(vec![U8.into(), U2.into()]), + Core::FullLeftShift8_4 => SourceJetClassification::Custom(vec![U8.into(), U4.into()]), + Core::FullLeftShift16_1 => SourceJetClassification::Custom(vec![U16.into(), U1.into()]), + Core::FullLeftShift16_2 => SourceJetClassification::Custom(vec![U16.into(), U2.into()]), + Core::FullLeftShift16_4 => SourceJetClassification::Custom(vec![U16.into(), U4.into()]), + Core::FullLeftShift16_8 => SourceJetClassification::Custom(vec![U16.into(), U8.into()]), + Core::FullLeftShift32_1 => SourceJetClassification::Custom(vec![U32.into(), U1.into()]), + Core::FullLeftShift32_2 => SourceJetClassification::Custom(vec![U32.into(), U2.into()]), + Core::FullLeftShift32_4 => SourceJetClassification::Custom(vec![U32.into(), U4.into()]), + Core::FullLeftShift32_8 => SourceJetClassification::Custom(vec![U32.into(), U8.into()]), + Core::FullLeftShift32_16 => SourceJetClassification::Custom(vec![U32.into(), U16.into()]), + Core::FullLeftShift64_1 => SourceJetClassification::Custom(vec![U64.into(), U1.into()]), + Core::FullLeftShift64_2 => SourceJetClassification::Custom(vec![U64.into(), U2.into()]), + Core::FullLeftShift64_4 => SourceJetClassification::Custom(vec![U64.into(), U4.into()]), + Core::FullLeftShift64_8 => SourceJetClassification::Custom(vec![U64.into(), U8.into()]), + Core::FullLeftShift64_16 => SourceJetClassification::Custom(vec![U64.into(), U16.into()]), + Core::FullLeftShift64_32 => SourceJetClassification::Custom(vec![U64.into(), U32.into()]), + Core::FullRightShift8_1 => SourceJetClassification::Custom(vec![U1.into(), U8.into()]), + Core::FullRightShift8_2 => SourceJetClassification::Custom(vec![U2.into(), U8.into()]), + Core::FullRightShift8_4 => SourceJetClassification::Custom(vec![U4.into(), U8.into()]), + Core::FullRightShift16_1 => SourceJetClassification::Custom(vec![U1.into(), U16.into()]), + Core::FullRightShift16_2 => SourceJetClassification::Custom(vec![U2.into(), U16.into()]), + Core::FullRightShift16_4 => SourceJetClassification::Custom(vec![U4.into(), U16.into()]), + Core::FullRightShift16_8 => SourceJetClassification::Custom(vec![U8.into(), U16.into()]), + Core::FullRightShift32_1 => SourceJetClassification::Custom(vec![U1.into(), U32.into()]), + Core::FullRightShift32_2 => SourceJetClassification::Custom(vec![U2.into(), U32.into()]), + Core::FullRightShift32_4 => SourceJetClassification::Custom(vec![U4.into(), U32.into()]), + Core::FullRightShift32_8 => SourceJetClassification::Custom(vec![U8.into(), U32.into()]), + Core::FullRightShift32_16 => SourceJetClassification::Custom(vec![U16.into(), U32.into()]), + Core::FullRightShift64_1 => SourceJetClassification::Custom(vec![U1.into(), U64.into()]), + Core::FullRightShift64_2 => SourceJetClassification::Custom(vec![U2.into(), U64.into()]), + Core::FullRightShift64_4 => SourceJetClassification::Custom(vec![U4.into(), U64.into()]), + Core::FullRightShift64_8 => SourceJetClassification::Custom(vec![U8.into(), U64.into()]), + Core::FullRightShift64_16 => SourceJetClassification::Custom(vec![U16.into(), U64.into()]), + Core::FullRightShift64_32 => SourceJetClassification::Custom(vec![U32.into(), U64.into()]), + Core::LeftShiftWith8 | Core::RightShiftWith8 => { + SourceJetClassification::Custom(vec![U1.into(), U4.into(), U8.into()]) + } + Core::LeftShiftWith16 | Core::RightShiftWith16 => { + SourceJetClassification::Custom(vec![U1.into(), U4.into(), U16.into()]) + } + Core::LeftShiftWith32 | Core::RightShiftWith32 => { + SourceJetClassification::Custom(vec![U1.into(), U8.into(), U32.into()]) + } + Core::LeftShiftWith64 | Core::RightShiftWith64 => { + SourceJetClassification::Custom(vec![U1.into(), U8.into(), U64.into()]) + } + Core::LeftShift8 | Core::RightShift8 | Core::LeftRotate8 | Core::RightRotate8 => { + SourceJetClassification::Custom(vec![U4.into(), U8.into()]) + } + Core::LeftShift16 | Core::RightShift16 | Core::LeftRotate16 | Core::RightRotate16 => { + SourceJetClassification::Custom(vec![U4.into(), U16.into()]) + } + Core::LeftShift32 | Core::RightShift32 | Core::LeftRotate32 | Core::RightRotate32 => { + SourceJetClassification::Custom(vec![U8.into(), U32.into()]) + } + Core::LeftShift64 | Core::RightShift64 | Core::LeftRotate64 | Core::RightRotate64 => { + SourceJetClassification::Custom(vec![U8.into(), U64.into()]) + } + /* + * Arithmetic + */ + Core::One8 | Core::One16 | Core::One32 | Core::One64 => SourceJetClassification::Unary, + Core::Increment8 | Core::Negate8 | Core::Decrement8 | Core::IsZero8 | Core::IsOne8 => { + SourceJetClassification::Unary + } + Core::Increment16 | Core::Negate16 | Core::Decrement16 | Core::IsZero16 | Core::IsOne16 => { + SourceJetClassification::Unary + } + Core::Increment32 | Core::Negate32 | Core::Decrement32 | Core::IsZero32 | Core::IsOne32 => { + SourceJetClassification::Unary + } + Core::Increment64 | Core::Negate64 | Core::Decrement64 | Core::IsZero64 | Core::IsOne64 => { + SourceJetClassification::Unary + } + Core::Add8 + | Core::Subtract8 + | Core::Multiply8 + | Core::Le8 + | Core::Lt8 + | Core::Min8 + | Core::Max8 + | Core::DivMod8 + | Core::Divide8 + | Core::Modulo8 + | Core::Divides8 => SourceJetClassification::Binary, + Core::Add16 + | Core::Subtract16 + | Core::Multiply16 + | Core::Le16 + | Core::Lt16 + | Core::Min16 + | Core::Max16 + | Core::DivMod16 + | Core::Divide16 + | Core::Modulo16 + | Core::Divides16 => SourceJetClassification::Binary, + Core::Add32 + | Core::Subtract32 + | Core::Multiply32 + | Core::Le32 + | Core::Lt32 + | Core::Min32 + | Core::Max32 + | Core::DivMod32 + | Core::Divide32 + | Core::Modulo32 + | Core::Divides32 => SourceJetClassification::Binary, + Core::Add64 + | Core::Subtract64 + | Core::Multiply64 + | Core::Le64 + | Core::Lt64 + | Core::Min64 + | Core::Max64 + | Core::DivMod64 + | Core::Divide64 + | Core::Modulo64 + | Core::Divides64 => SourceJetClassification::Binary, + Core::DivMod128_64 => SourceJetClassification::Custom(vec![U128.into(), U64.into()]), + Core::FullAdd8 | Core::FullSubtract8 => { + SourceJetClassification::Custom(vec![bool(), U8.into(), U8.into()]) + } + Core::FullAdd16 | Core::FullSubtract16 => { + SourceJetClassification::Custom(vec![bool(), U16.into(), U16.into()]) + } + Core::FullAdd32 | Core::FullSubtract32 => { + SourceJetClassification::Custom(vec![bool(), U32.into(), U32.into()]) + } + Core::FullAdd64 | Core::FullSubtract64 => { + SourceJetClassification::Custom(vec![bool(), U64.into(), U64.into()]) + } + Core::FullIncrement8 | Core::FullDecrement8 => { + SourceJetClassification::Custom(vec![bool(), U8.into()]) + } + Core::FullIncrement16 | Core::FullDecrement16 => { + SourceJetClassification::Custom(vec![bool(), U16.into()]) + } + Core::FullIncrement32 | Core::FullDecrement32 => { + SourceJetClassification::Custom(vec![bool(), U32.into()]) + } + Core::FullIncrement64 | Core::FullDecrement64 => { + SourceJetClassification::Custom(vec![bool(), U64.into()]) + } + Core::FullMultiply8 => SourceJetClassification::Quaternary, + Core::FullMultiply16 => SourceJetClassification::Quaternary, + Core::FullMultiply32 => SourceJetClassification::Quaternary, + Core::FullMultiply64 => SourceJetClassification::Quaternary, + Core::Median8 => SourceJetClassification::Ternary, + Core::Median16 => SourceJetClassification::Ternary, + Core::Median32 => SourceJetClassification::Ternary, + Core::Median64 => SourceJetClassification::Ternary, + /* + * Hash functions + */ + Core::Sha256Iv | Core::Sha256Ctx8Init => SourceJetClassification::Unary, + Core::Sha256Block => SourceJetClassification::Ternary, + Core::Sha256Ctx8Add1 => SourceJetClassification::Custom(vec![Ctx8.into(), U8.into()]), + Core::Sha256Ctx8Add2 => SourceJetClassification::Custom(vec![Ctx8.into(), U16.into()]), + Core::Sha256Ctx8Add4 => SourceJetClassification::Custom(vec![Ctx8.into(), U32.into()]), + Core::Sha256Ctx8Add8 => SourceJetClassification::Custom(vec![Ctx8.into(), U64.into()]), + Core::Sha256Ctx8Add16 => SourceJetClassification::Custom(vec![Ctx8.into(), U128.into()]), + Core::Sha256Ctx8Add32 => SourceJetClassification::Custom(vec![Ctx8.into(), U256.into()]), + Core::Sha256Ctx8Add64 => SourceJetClassification::Custom(vec![Ctx8.into(), array(U8, 64)]), + Core::Sha256Ctx8Add128 => { + SourceJetClassification::Custom(vec![Ctx8.into(), array(U8, 128)]) + } + Core::Sha256Ctx8Add256 => { + SourceJetClassification::Custom(vec![Ctx8.into(), array(U8, 256)]) + } + Core::Sha256Ctx8Add512 => { + SourceJetClassification::Custom(vec![Ctx8.into(), array(U8, 512)]) + } + Core::Sha256Ctx8AddBuffer511 => { + SourceJetClassification::Custom(vec![Ctx8.into(), list(U8, 512)]) + } + Core::Sha256Ctx8Finalize => SourceJetClassification::Custom(vec![Ctx8.into()]), + /* + * Elliptic curve functions + */ + // XXX: Nonstandard tuple + Core::PointVerify1 => SourceJetClassification::Custom(vec![ + tuple([tuple([Scalar, Point]), Scalar.into()]), + Point.into(), + ]), + Core::Decompress => SourceJetClassification::Custom(vec![Point.into()]), + // XXX: Nonstandard tuple + Core::LinearVerify1 => SourceJetClassification::Custom(vec![ + tuple([tuple([Scalar, Ge]), Scalar.into()]), + Ge.into(), + ]), + // XXX: Nonstandard tuple + Core::LinearCombination1 => { + SourceJetClassification::Custom(vec![tuple([Scalar, Gej]), Scalar.into()]) + } + Core::Scale => SourceJetClassification::Custom(vec![Scalar.into(), Gej.into()]), + Core::Generate => SourceJetClassification::Custom(vec![Scalar.into()]), + Core::GejInfinity => SourceJetClassification::Unary, + Core::GejNormalize + | Core::GejNegate + | Core::GejDouble + | Core::GejIsInfinity + | Core::GejYIsOdd + | Core::GejIsOnCurve => SourceJetClassification::Custom(vec![Gej.into()]), + Core::GeNegate | Core::GeIsOnCurve => SourceJetClassification::Custom(vec![Ge.into()]), + Core::GejAdd | Core::GejEquiv => { + SourceJetClassification::Custom(vec![Gej.into(), Gej.into()]) + } + Core::GejGeAddEx | Core::GejGeAdd | Core::GejGeEquiv => { + SourceJetClassification::Custom(vec![Gej.into(), Ge.into()]) + } + Core::GejRescale => SourceJetClassification::Custom(vec![Gej.into(), Fe.into()]), + Core::GejXEquiv => SourceJetClassification::Custom(vec![Fe.into(), Gej.into()]), + Core::ScalarAdd | Core::ScalarMultiply => { + SourceJetClassification::Custom(vec![Scalar.into(), Scalar.into()]) + } + Core::ScalarNormalize + | Core::ScalarNegate + | Core::ScalarSquare + | Core::ScalarInvert + | Core::ScalarMultiplyLambda + | Core::ScalarIsZero => SourceJetClassification::Custom(vec![Scalar.into()]), + Core::FeNormalize + | Core::FeNegate + | Core::FeSquare + | Core::FeMultiplyBeta + | Core::FeInvert + | Core::FeSquareRoot + | Core::FeIsZero + | Core::FeIsOdd + | Core::Swu => SourceJetClassification::Custom(vec![Fe.into()]), + Core::FeAdd | Core::FeMultiply => { + SourceJetClassification::Custom(vec![Fe.into(), Fe.into()]) + } + Core::HashToCurve => SourceJetClassification::Unary, + /* + * Digital signatures + */ + // XXX: Nonstandard tuple + Core::CheckSigVerify => { + SourceJetClassification::Custom(vec![tuple([Pubkey, Message64]), Signature.into()]) + } + // XXX: Nonstandard tuple + Core::Bip0340Verify => { + SourceJetClassification::Custom(vec![tuple([Pubkey, Message]), Signature.into()]) + } + /* + * Bitcoin (without primitives) + */ + Core::TapdataInit => SourceJetClassification::Unary, + Core::ParseLock | Core::ParseSequence => SourceJetClassification::Unary, + } +} + +fn target_jet_classification(jet: Core) -> TargetJetClassification { + match jet { + /* + * ============================== + * Core jets + * ============================== + * + * Multi-bit logic + */ + Core::Verify => TargetJetClassification::Unary, + Core::Some1 + | Core::Some8 + | Core::Some16 + | Core::Some32 + | Core::Some64 + | Core::All8 + | Core::All16 + | Core::All32 + | Core::All64 + | Core::Eq1 + | Core::Eq8 + | Core::Eq16 + | Core::Eq32 + | Core::Eq64 + | Core::Eq256 => TargetJetClassification::Custom(bool()), + Core::Low1 + | Core::High1 + | Core::Complement1 + | Core::And1 + | Core::Or1 + | Core::Xor1 + | Core::Maj1 + | Core::XorXor1 + | Core::Ch1 + | Core::Leftmost8_1 + | Core::Rightmost8_1 + | Core::Leftmost16_1 + | Core::Rightmost16_1 + | Core::Leftmost32_1 + | Core::Rightmost32_1 + | Core::Leftmost64_1 + | Core::Rightmost64_1 => TargetJetClassification::Unary, + Core::Leftmost8_2 + | Core::Rightmost8_2 + | Core::Leftmost16_2 + | Core::Rightmost16_2 + | Core::Leftmost32_2 + | Core::Rightmost32_2 + | Core::Leftmost64_2 + | Core::Rightmost64_2 => TargetJetClassification::Unary, + Core::Leftmost8_4 + | Core::Rightmost8_4 + | Core::Leftmost16_4 + | Core::Rightmost16_4 + | Core::Leftmost32_4 + | Core::Rightmost32_4 + | Core::Leftmost64_4 + | Core::Rightmost64_4 => TargetJetClassification::Unary, + Core::Low8 + | Core::High8 + | Core::Complement8 + | Core::And8 + | Core::Or8 + | Core::Xor8 + | Core::Maj8 + | Core::XorXor8 + | Core::Ch8 + | Core::Leftmost16_8 + | Core::Rightmost16_8 + | Core::Leftmost32_8 + | Core::Rightmost32_8 + | Core::Leftmost64_8 + | Core::Rightmost64_8 + | Core::LeftPadLow1_8 + | Core::LeftPadHigh1_8 + | Core::LeftExtend1_8 + | Core::RightPadLow1_8 + | Core::RightPadHigh1_8 + | Core::LeftShiftWith8 + | Core::RightShiftWith8 + | Core::LeftShift8 + | Core::RightShift8 + | Core::LeftRotate8 + | Core::RightRotate8 => TargetJetClassification::Unary, + Core::Low16 + | Core::High16 + | Core::Complement16 + | Core::And16 + | Core::Or16 + | Core::Xor16 + | Core::Maj16 + | Core::XorXor16 + | Core::Ch16 + | Core::Leftmost32_16 + | Core::Rightmost32_16 + | Core::Leftmost64_16 + | Core::Rightmost64_16 + | Core::LeftPadLow1_16 + | Core::LeftPadHigh1_16 + | Core::LeftExtend1_16 + | Core::RightPadLow1_16 + | Core::RightPadHigh1_16 + | Core::LeftPadLow8_16 + | Core::LeftPadHigh8_16 + | Core::LeftExtend8_16 + | Core::RightPadLow8_16 + | Core::RightPadHigh8_16 + | Core::RightExtend8_16 + | Core::LeftShiftWith16 + | Core::RightShiftWith16 + | Core::LeftShift16 + | Core::RightShift16 + | Core::LeftRotate16 + | Core::RightRotate16 => TargetJetClassification::Unary, + Core::Low32 + | Core::High32 + | Core::Complement32 + | Core::And32 + | Core::Or32 + | Core::Xor32 + | Core::Maj32 + | Core::XorXor32 + | Core::Ch32 + | Core::Leftmost64_32 + | Core::Rightmost64_32 + | Core::LeftPadLow1_32 + | Core::LeftPadHigh1_32 + | Core::LeftExtend1_32 + | Core::RightPadLow1_32 + | Core::RightPadHigh1_32 + | Core::LeftPadLow8_32 + | Core::LeftPadHigh8_32 + | Core::LeftExtend8_32 + | Core::RightPadLow8_32 + | Core::RightPadHigh8_32 + | Core::RightExtend8_32 + | Core::LeftPadLow16_32 + | Core::LeftPadHigh16_32 + | Core::LeftExtend16_32 + | Core::RightPadLow16_32 + | Core::RightPadHigh16_32 + | Core::RightExtend16_32 + | Core::LeftShiftWith32 + | Core::RightShiftWith32 + | Core::LeftShift32 + | Core::RightShift32 + | Core::LeftRotate32 + | Core::RightRotate32 => TargetJetClassification::Unary, + Core::Low64 + | Core::High64 + | Core::Complement64 + | Core::And64 + | Core::Or64 + | Core::Xor64 + | Core::Maj64 + | Core::XorXor64 + | Core::Ch64 + | Core::LeftPadLow1_64 + | Core::LeftPadHigh1_64 + | Core::LeftExtend1_64 + | Core::RightPadLow1_64 + | Core::RightPadHigh1_64 + | Core::LeftPadLow8_64 + | Core::LeftPadHigh8_64 + | Core::LeftExtend8_64 + | Core::RightPadLow8_64 + | Core::RightPadHigh8_64 + | Core::RightExtend8_64 + | Core::LeftPadLow16_64 + | Core::LeftPadHigh16_64 + | Core::LeftExtend16_64 + | Core::RightPadLow16_64 + | Core::RightPadHigh16_64 + | Core::RightExtend16_64 + | Core::LeftPadLow32_64 + | Core::LeftPadHigh32_64 + | Core::LeftExtend32_64 + | Core::RightPadLow32_64 + | Core::RightPadHigh32_64 + | Core::RightExtend32_64 + | Core::LeftShiftWith64 + | Core::RightShiftWith64 + | Core::LeftShift64 + | Core::RightShift64 + | Core::LeftRotate64 + | Core::RightRotate64 => TargetJetClassification::Unary, + Core::FullLeftShift8_1 => TargetJetClassification::Custom(tuple([U1, U8])), + Core::FullLeftShift8_2 => TargetJetClassification::Custom(tuple([U2, U8])), + Core::FullLeftShift8_4 => TargetJetClassification::Custom(tuple([U4, U8])), + Core::FullLeftShift16_1 => TargetJetClassification::Custom(tuple([U1, U16])), + Core::FullLeftShift16_2 => TargetJetClassification::Custom(tuple([U2, U16])), + Core::FullLeftShift16_4 => TargetJetClassification::Custom(tuple([U4, U16])), + Core::FullLeftShift16_8 => TargetJetClassification::Custom(tuple([U8, U16])), + Core::FullLeftShift32_1 => TargetJetClassification::Custom(tuple([U1, U32])), + Core::FullLeftShift32_2 => TargetJetClassification::Custom(tuple([U2, U32])), + Core::FullLeftShift32_4 => TargetJetClassification::Custom(tuple([U4, U32])), + Core::FullLeftShift32_8 => TargetJetClassification::Custom(tuple([U8, U32])), + Core::FullLeftShift32_16 => TargetJetClassification::Custom(tuple([U16, U32])), + Core::FullLeftShift64_1 => TargetJetClassification::Custom(tuple([U1, U64])), + Core::FullLeftShift64_2 => TargetJetClassification::Custom(tuple([U2, U64])), + Core::FullLeftShift64_4 => TargetJetClassification::Custom(tuple([U4, U64])), + Core::FullLeftShift64_8 => TargetJetClassification::Custom(tuple([U8, U64])), + Core::FullLeftShift64_16 => TargetJetClassification::Custom(tuple([U16, U64])), + Core::FullLeftShift64_32 => TargetJetClassification::Custom(tuple([U32, U64])), + Core::FullRightShift8_1 => TargetJetClassification::Custom(tuple([U8, U1])), + Core::FullRightShift8_2 => TargetJetClassification::Custom(tuple([U8, U2])), + Core::FullRightShift8_4 => TargetJetClassification::Custom(tuple([U8, U4])), + Core::FullRightShift16_1 => TargetJetClassification::Custom(tuple([U16, U1])), + Core::FullRightShift16_2 => TargetJetClassification::Custom(tuple([U16, U2])), + Core::FullRightShift16_4 => TargetJetClassification::Custom(tuple([U16, U4])), + Core::FullRightShift16_8 => TargetJetClassification::Custom(tuple([U16, U8])), + Core::FullRightShift32_1 => TargetJetClassification::Custom(tuple([U32, U1])), + Core::FullRightShift32_2 => TargetJetClassification::Custom(tuple([U32, U2])), + Core::FullRightShift32_4 => TargetJetClassification::Custom(tuple([U32, U4])), + Core::FullRightShift32_8 => TargetJetClassification::Custom(tuple([U32, U8])), + Core::FullRightShift32_16 => TargetJetClassification::Custom(tuple([U32, U16])), + Core::FullRightShift64_1 => TargetJetClassification::Custom(tuple([U64, U1])), + Core::FullRightShift64_2 => TargetJetClassification::Custom(tuple([U64, U2])), + Core::FullRightShift64_4 => TargetJetClassification::Custom(tuple([U64, U4])), + Core::FullRightShift64_8 => TargetJetClassification::Custom(tuple([U64, U8])), + Core::FullRightShift64_16 => TargetJetClassification::Custom(tuple([U64, U16])), + Core::FullRightShift64_32 => TargetJetClassification::Custom(tuple([U64, U32])), + /* + * Arithmetic + */ + Core::Le8 + | Core::Lt8 + | Core::Le16 + | Core::Lt16 + | Core::Le32 + | Core::Lt32 + | Core::Le64 + | Core::Lt64 + | Core::IsZero8 + | Core::IsOne8 + | Core::IsZero16 + | Core::IsOne16 + | Core::IsZero32 + | Core::IsOne32 + | Core::IsZero64 + | Core::IsOne64 + | Core::Divides8 + | Core::Divides16 + | Core::Divides32 + | Core::Divides64 => TargetJetClassification::Custom(bool()), + Core::One8 | Core::Min8 | Core::Max8 | Core::Divide8 | Core::Modulo8 | Core::Median8 => { + TargetJetClassification::Unary + } + Core::One16 + | Core::Min16 + | Core::Max16 + | Core::Divide16 + | Core::Modulo16 + | Core::Multiply8 + | Core::FullMultiply8 + | Core::Median16 => TargetJetClassification::Unary, + Core::One32 + | Core::Min32 + | Core::Max32 + | Core::Divide32 + | Core::Modulo32 + | Core::Multiply16 + | Core::FullMultiply16 + | Core::Median32 => TargetJetClassification::Unary, + Core::One64 + | Core::Min64 + | Core::Max64 + | Core::Divide64 + | Core::Modulo64 + | Core::Multiply32 + | Core::FullMultiply32 + | Core::Median64 => TargetJetClassification::Unary, + Core::Multiply64 | Core::FullMultiply64 => TargetJetClassification::Unary, + Core::Increment8 + | Core::Negate8 + | Core::Decrement8 + | Core::Add8 + | Core::Subtract8 + | Core::FullAdd8 + | Core::FullSubtract8 + | Core::FullIncrement8 + | Core::FullDecrement8 => TargetJetClassification::Custom(tuple([bool(), U8.into()])), + Core::Increment16 + | Core::Negate16 + | Core::Decrement16 + | Core::Add16 + | Core::Subtract16 + | Core::FullAdd16 + | Core::FullSubtract16 + | Core::FullIncrement16 + | Core::FullDecrement16 => TargetJetClassification::Custom(tuple([bool(), U16.into()])), + Core::Increment32 + | Core::Negate32 + | Core::Decrement32 + | Core::Add32 + | Core::Subtract32 + | Core::FullAdd32 + | Core::FullSubtract32 + | Core::FullIncrement32 + | Core::FullDecrement32 => TargetJetClassification::Custom(tuple([bool(), U32.into()])), + Core::Increment64 + | Core::Negate64 + | Core::Decrement64 + | Core::Add64 + | Core::Subtract64 + | Core::FullAdd64 + | Core::FullSubtract64 + | Core::FullIncrement64 + | Core::FullDecrement64 => TargetJetClassification::Custom(tuple([bool(), U64.into()])), + Core::DivMod8 => TargetJetClassification::Custom(tuple([U8, U8])), + Core::DivMod16 => TargetJetClassification::Custom(tuple([U16, U16])), + Core::DivMod32 => TargetJetClassification::Custom(tuple([U32, U32])), + Core::DivMod64 => TargetJetClassification::Custom(tuple([U64, U64])), + Core::DivMod128_64 => TargetJetClassification::Custom(tuple([U64, U64])), + /* + * Hash functions + */ + Core::Sha256Iv | Core::Sha256Block | Core::Sha256Ctx8Finalize => { + TargetJetClassification::Unary + } + Core::Sha256Ctx8Init + | Core::Sha256Ctx8Add1 + | Core::Sha256Ctx8Add2 + | Core::Sha256Ctx8Add4 + | Core::Sha256Ctx8Add8 + | Core::Sha256Ctx8Add16 + | Core::Sha256Ctx8Add32 + | Core::Sha256Ctx8Add64 + | Core::Sha256Ctx8Add128 + | Core::Sha256Ctx8Add256 + | Core::Sha256Ctx8Add512 + | Core::Sha256Ctx8AddBuffer511 => TargetJetClassification::Custom(Ctx8.into()), + /* + * Elliptic curve functions + */ + Core::PointVerify1 | Core::LinearVerify1 => TargetJetClassification::Unary, + Core::GejIsInfinity + | Core::GejEquiv + | Core::GejGeEquiv + | Core::GejXEquiv + | Core::GejYIsOdd + | Core::GejIsOnCurve + | Core::GeIsOnCurve + | Core::ScalarIsZero + | Core::FeIsZero + | Core::FeIsOdd => TargetJetClassification::Custom(bool()), + Core::GeNegate | Core::HashToCurve | Core::Swu => { + TargetJetClassification::Custom(Ge.into()) + } + Core::Decompress | Core::GejNormalize => TargetJetClassification::Custom(option(Ge)), + Core::LinearCombination1 + | Core::Scale + | Core::Generate + | Core::GejInfinity + | Core::GejNegate + | Core::GejDouble + | Core::GejAdd + | Core::GejGeAdd + | Core::GejRescale => TargetJetClassification::Custom(Gej.into()), + Core::GejGeAddEx => TargetJetClassification::Custom(tuple([Fe, Gej])), + Core::ScalarNormalize + | Core::ScalarNegate + | Core::ScalarAdd + | Core::ScalarSquare + | Core::ScalarMultiply + | Core::ScalarMultiplyLambda + | Core::ScalarInvert => TargetJetClassification::Custom(Scalar.into()), + Core::FeNormalize + | Core::FeNegate + | Core::FeAdd + | Core::FeSquare + | Core::FeMultiply + | Core::FeMultiplyBeta + | Core::FeInvert => TargetJetClassification::Custom(Fe.into()), + Core::FeSquareRoot => TargetJetClassification::Custom(option(Fe)), + /* + * Digital signatures + */ + Core::CheckSigVerify | Core::Bip0340Verify => TargetJetClassification::Unary, + /* + * Bitcoin (without primitives) + */ + Core::ParseLock => TargetJetClassification::Custom(either(Height, Time)), + Core::ParseSequence => TargetJetClassification::Custom(option(either(Distance, Duration))), + Core::TapdataInit => TargetJetClassification::Custom(Ctx8.into()), + } +} diff --git a/src/jet.rs b/src/jet/elements.rs similarity index 91% rename from src/jet.rs rename to src/jet/elements.rs index 3c9aee16..da41753c 100644 --- a/src/jet.rs +++ b/src/jet/elements.rs @@ -1,48 +1,17 @@ -use crate::num::NonZeroPow2Usize; -use crate::num::Pow2Usize; use crate::types::BuiltinAlias::*; use crate::types::UIntType::*; -use crate::types::*; -use simplicity::jet::DynJet; -use simplicity::jet::Elements; -use simplicity::jet::Jet; +use super::*; -pub trait JetHL: DynJet + Jet + std::fmt::Debug + Send + Sync + 'static { - fn source_type(&self) -> Vec; - fn target_type(&self) -> AliasedType; - fn is_disabled(&self) -> bool; - fn clone_box(&self) -> Box; - fn as_jet(&self) -> &dyn Jet; -} - -impl Clone for Box { - fn clone(&self) -> Self { - (**self).clone_box() - } -} - -impl PartialEq for Box { - fn eq(&self, other: &Self) -> bool { - (**self).dyn_eq(other.as_jet()) - } -} - -impl Eq for Box {} - -impl std::hash::Hash for Box { - fn hash(&self, state: &mut H) { - (**self).dyn_hash(state) - } -} +use simplicity::jet::{Elements, Jet}; impl JetHL for Elements { - fn source_type(&self) -> Vec { - source_type(*self) + fn source_jet_classification(&self) -> SourceJetClassification { + source_jet_classification(*self) } - fn target_type(&self) -> AliasedType { - target_type(*self) + fn target_jet_classification(&self) -> TargetJetClassification { + target_jet_classification(*self) } fn is_disabled(&self) -> bool { @@ -58,57 +27,6 @@ impl JetHL for Elements { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum SourceJetClassification { - Unary, - Binary, - Ternary, - Quaternary, - Custom(Vec), -} - -impl SourceJetClassification { - fn divisor(&self) -> usize { - match self { - SourceJetClassification::Unary => 1, - SourceJetClassification::Binary => 2, - SourceJetClassification::Ternary => 3, - SourceJetClassification::Quaternary => 4, - SourceJetClassification::Custom(types) => types.len(), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum TargetJetClassification { - Unary, - Custom(AliasedType), -} - -fn tuple, I: IntoIterator>(elements: I) -> AliasedType { - AliasedType::tuple(elements.into_iter().map(A::into)) -} - -fn array>(element: A, size: usize) -> AliasedType { - AliasedType::array(element.into(), size) -} - -fn list>(element: A, bound: usize) -> AliasedType { - AliasedType::list(element.into(), NonZeroPow2Usize::new(bound).unwrap()) -} - -fn bool() -> AliasedType { - AliasedType::boolean() -} - -fn either, B: Into>(left: A, right: B) -> AliasedType { - AliasedType::either(left.into(), right.into()) -} - -fn option>(inner: A) -> AliasedType { - AliasedType::option(inner.into()) -} - fn source_jet_classification(jet: Elements) -> SourceJetClassification { match jet { /* @@ -706,26 +624,6 @@ fn source_jet_classification(jet: Elements) -> SourceJetClassification { } } -pub fn source_type(jet: Elements) -> Vec { - let source_class = source_jet_classification(jet); - if let SourceJetClassification::Custom(custom_type) = source_class { - return custom_type; - } - - let divisor = source_class.divisor(); - let component_bit_width = jet.source_ty().to_bit_width() / divisor; - if component_bit_width == 0 { - return Vec::new(); - } - - let pow_of_2 = Pow2Usize::new(component_bit_width) - .expect("the width of the source type should be power of 2"); - let num_type = - UIntType::from_bit_width(pow_of_2).expect("the source type should be one of defined"); - - vec![AliasedType::from(num_type); divisor] -} - fn target_jet_classification(jet: Elements) -> TargetJetClassification { match jet { /* @@ -1253,52 +1151,3 @@ fn target_jet_classification(jet: Elements) -> TargetJetClassification { } } } - -pub fn target_type(jet: Elements) -> AliasedType { - if let TargetJetClassification::Custom(custom_type) = target_jet_classification(jet) { - return custom_type; - } - - let bit_width = jet.target_ty().to_bit_width(); - if bit_width == 0 { - return AliasedType::unit(); - } - - let pow_of_2 = Pow2Usize::new(bit_width).expect("should be fine"); - let num_type = UIntType::from_bit_width(pow_of_2).expect("should exist"); - AliasedType::from(num_type) -} - -#[cfg(test)] -mod tests { - use super::*; - use simplicity::jet::Jet; - - #[test] - fn compatible_source_type() { - for jet in Elements::ALL { - let resolved_ty = ResolvedType::tuple( - jet.source_type() - .into_iter() - .map(|t| t.resolve_builtin().unwrap()), - ); - let structural_ty = StructuralType::from(&resolved_ty); - let simplicity_ty = jet.source_ty().to_final(); - - println!("{jet}"); - assert_eq!(structural_ty.as_ref(), simplicity_ty.as_ref()); - } - } - - #[test] - fn compatible_target_type() { - for jet in Elements::ALL { - let resolved_ty = jet.target_type().resolve_builtin().unwrap(); - let structural_ty = StructuralType::from(&resolved_ty); - let simplicity_ty = jet.target_ty().to_final(); - - println!("{jet}"); - assert_eq!(structural_ty.as_ref(), simplicity_ty.as_ref()); - } - } -} diff --git a/src/jet/mod.rs b/src/jet/mod.rs new file mode 100644 index 00000000..822c4967 --- /dev/null +++ b/src/jet/mod.rs @@ -0,0 +1,157 @@ +pub mod core; +pub mod elements; + +use crate::num::NonZeroPow2Usize; +use crate::num::Pow2Usize; +use crate::types::*; + +use simplicity::jet::DynJet; +use simplicity::jet::Jet; + +pub trait JetHL: DynJet + Jet + std::fmt::Debug + Send + Sync + 'static { + fn source_jet_classification(&self) -> SourceJetClassification; + fn target_jet_classification(&self) -> TargetJetClassification; + fn is_disabled(&self) -> bool; + fn clone_box(&self) -> Box; + fn as_jet(&self) -> &dyn Jet; +} + +impl Clone for Box { + fn clone(&self) -> Self { + (**self).clone_box() + } +} + +impl PartialEq for Box { + fn eq(&self, other: &Self) -> bool { + (**self).dyn_eq(other.as_jet()) + } +} + +impl Eq for Box {} + +impl std::hash::Hash for Box { + fn hash(&self, state: &mut H) { + (**self).dyn_hash(state) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum SourceJetClassification { + Unary, + Binary, + Ternary, + Quaternary, + Custom(Vec), +} + +impl SourceJetClassification { + pub fn divisor(&self) -> usize { + match self { + SourceJetClassification::Unary => 1, + SourceJetClassification::Binary => 2, + SourceJetClassification::Ternary => 3, + SourceJetClassification::Quaternary => 4, + SourceJetClassification::Custom(types) => types.len(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum TargetJetClassification { + Unary, + Custom(AliasedType), +} + +pub fn tuple, I: IntoIterator>(elements: I) -> AliasedType { + AliasedType::tuple(elements.into_iter().map(A::into)) +} + +pub fn array>(element: A, size: usize) -> AliasedType { + AliasedType::array(element.into(), size) +} + +pub fn list>(element: A, bound: usize) -> AliasedType { + AliasedType::list(element.into(), NonZeroPow2Usize::new(bound).unwrap()) +} + +pub fn bool() -> AliasedType { + AliasedType::boolean() +} + +pub fn either, B: Into>(left: A, right: B) -> AliasedType { + AliasedType::either(left.into(), right.into()) +} + +pub fn option>(inner: A) -> AliasedType { + AliasedType::option(inner.into()) +} + +pub fn source_type(jet: &dyn JetHL) -> Vec { + let source_class = jet.source_jet_classification(); + if let SourceJetClassification::Custom(custom_type) = source_class { + return custom_type; + } + + let divisor = source_class.divisor(); + let component_bit_width = jet.source_ty().to_bit_width() / divisor; + if component_bit_width == 0 { + return Vec::new(); + } + + let pow_of_2 = Pow2Usize::new(component_bit_width) + .expect("the width of the source type should be power of 2"); + let num_type = + UIntType::from_bit_width(pow_of_2).expect("the source type should be one of defined"); + + vec![AliasedType::from(num_type); divisor] +} + +pub fn target_type(jet: &dyn JetHL) -> AliasedType { + if let TargetJetClassification::Custom(custom_type) = jet.target_jet_classification() { + return custom_type; + } + + let bit_width = jet.target_ty().to_bit_width(); + if bit_width == 0 { + return AliasedType::unit(); + } + + let pow_of_2 = Pow2Usize::new(bit_width).expect("should be fine"); + let num_type = UIntType::from_bit_width(pow_of_2).expect("should exist"); + AliasedType::from(num_type) +} + +#[cfg(test)] +mod tests { + use super::*; + use simplicity::jet::{Elements, Jet}; + + #[test] + fn compatible_source_type() { + for jet in Elements::ALL { + let resolved_ty = ResolvedType::tuple( + source_type(&jet) + .into_iter() + .map(|t| t.resolve_builtin().unwrap()), + ); + let structural_ty = StructuralType::from(&resolved_ty); + let simplicity_ty = jet.source_ty().to_final(); + + println!("{jet}"); + assert_eq!(structural_ty.as_ref(), simplicity_ty.as_ref()); + } + } + + #[test] + fn compatible_target_type() { + for jet in Elements::ALL { + let resolved_ty = target_type(&jet).resolve_builtin().unwrap(); + let structural_ty = StructuralType::from(&resolved_ty); + let simplicity_ty = jet.target_ty().to_final(); + + println!("{jet}"); + assert_eq!(structural_ty.as_ref(), simplicity_ty.as_ref()); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 707ce622..a7962dab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -412,7 +412,7 @@ pub trait ArbitraryOfType: Sized { #[cfg(test)] pub(crate) mod tests { - use crate::ast::ElementsJetHinter; + use crate::ast::{CoreJetHinter, ElementsJetHinter, JetHinter}; use crate::parse::ParseFromStr; use crate::resolution::tests::canon; use crate::resolution::DependencyMapBuilder; @@ -1023,6 +1023,54 @@ fn main() { .assert_run_success(); } + #[test] + fn test_compilation_against_different_jet_hinters() { + let code = r#"fn main() { + let (_, sum): (bool, u32) = jet::add_32(10, 20); + assert!(jet::eq_32(sum, 30)); + let and_result: u32 = jet::and_32(0xFF00FF00, 0x0F0F0F0F); + assert!(jet::eq_32(and_result, 0x0F000F00)); +}"#; + + let hinters: Vec> = vec![ + Box::new(CoreJetHinter::new()), + Box::new(ElementsJetHinter::new()), + ]; + + for hinter in hinters { + let program = TemplateProgram::new(code, hinter); + assert!( + program.is_ok(), + "TemplateProgram::new should successfully compile the same program with different jet hinters: {:?}", + program.err(), + ); + } + } + + #[test] + fn test_fail_with_different_jet_hinters() { + // Uses jets that exist only in Elements (not in Core). + let code = r#"fn main() { + let v: u32 = jet::version(); + let idx: u32 = jet::current_index(); + assert!(jet::eq_32(v, v)); + assert!(jet::eq_32(idx, idx)); +}"#; + + let elements_result = TemplateProgram::new(code, Box::new(ElementsJetHinter::new())); + assert!( + elements_result.is_ok(), + "ElementsJetHinter should compile Elements-specific jets: {:?}", + elements_result.err(), + ); + + let core_result = TemplateProgram::new(code, Box::new(CoreJetHinter::new())); + assert!( + core_result.is_err(), + "CoreJetHinter should fail to compile Elements-specific jets", + ); + } + #[cfg(feature = "serde")] mod regression { use super::TestCase; diff --git a/src/tracker.rs b/src/tracker.rs index 630dfa1a..d65675ec 100644 --- a/src/tracker.rs +++ b/src/tracker.rs @@ -6,7 +6,7 @@ use simplicity::{Ihr, RedeemNode, Value as SimValue}; use crate::array::Unfolder; use crate::debug::{DebugSymbols, TrackedCallName}; use crate::either::Either; -use crate::jet::JetHL; +use crate::jet::{source_type, target_type}; use crate::str::AliasName; use crate::types::AliasedType; use crate::value::StructuralValue; @@ -212,7 +212,7 @@ impl<'a> DefaultTracker<'a> { match output.clone() { NodeOutput::Success(mut output_frame) => { let target_ty = &node.arrow().target; - let jet_target_ty = resolve_jet_type(&jet.target_type()); + let jet_target_ty = resolve_jet_type(&target_type(&jet)); let output_value = SimValue::from_padded_bits(&mut output_frame, target_ty) .expect("output from bit machine is always well-formed"); @@ -319,7 +319,7 @@ impl ExecTracker for DefaultTracker<'_> { /// Parses jet input arguments from the bit machine's read frame. fn parse_jet_arguments(jet: Elements, input_frame: &mut FrameIter) -> Result, String> { - let source_types = jet.source_type(); + let source_types = source_type(&jet); if source_types.is_empty() { return Ok(vec![]); }