Skip to content

Commit 0445ef9

Browse files
committed
Merge #274: fix: Correct FullMultiply signatures and tracker argument decoding
353805a fix: Correct FullMultiply signatures and tracker argument decoding (metalurgical) Pull request description: Fix incorrect signatures for FullMultiply. Additionally fixes a bug in tracker, which was surfaced by this fix, so that it correctly decodes inputs. Changes: - FullMultiply((A,B),(C,D)) signatures corrected to FullMultiply(A,B,C,D) - Fix argument parsing in tracker by utilizing Unfolder - Removes `collect_product_elements` helper. - Adds regression test covering FullMultiply functions Furthermore, this keeps the semantics unchanged ((A*B) + C + D) while fixing the API surface and ensuring tracker compatibility. ACKs for top commit: apoelstra: ACK 353805a; successfully ran local tests KyrylR: ACK 353805a; successfully ran local tests; code review Tree-SHA512: 8cc168a18eb7444c70084f7f40fa0c8b531664ae82ce4211c8d2fc4e86478773b8c838d013986e1d7f26e3847f66846b30ebfdd76a501a5815a2f7b696155cfb
2 parents b4e74dd + 353805a commit 0445ef9

2 files changed

Lines changed: 100 additions & 32 deletions

File tree

src/jet.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,10 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
323323
Elements::FullIncrement16 | Elements::FullDecrement16 => vec![bool(), U16.into()],
324324
Elements::FullIncrement32 | Elements::FullDecrement32 => vec![bool(), U32.into()],
325325
Elements::FullIncrement64 | Elements::FullDecrement64 => vec![bool(), U64.into()],
326-
Elements::FullMultiply8 => vec![tuple([U8, U8]), tuple([U8, U8])],
327-
Elements::FullMultiply16 => vec![tuple([U16, U16]), tuple([U16, U16])],
328-
Elements::FullMultiply32 => vec![tuple([U32, U32]), tuple([U32, U32])],
329-
Elements::FullMultiply64 => vec![tuple([U64, U64]), tuple([U64, U64])],
326+
Elements::FullMultiply8 => vec![U8.into(), U8.into(), U8.into(), U8.into()],
327+
Elements::FullMultiply16 => vec![U16.into(), U16.into(), U16.into(), U16.into()],
328+
Elements::FullMultiply32 => vec![U32.into(), U32.into(), U32.into(), U32.into()],
329+
Elements::FullMultiply64 => vec![U64.into(), U64.into(), U64.into(), U64.into()],
330330
Elements::Median8 => vec![U8.into(), U8.into(), U8.into()],
331331
Elements::Median16 => vec![U16.into(), U16.into(), U16.into()],
332332
Elements::Median32 => vec![U32.into(), U32.into(), U32.into()],

src/tracker.rs

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use simplicity::bit_machine::{ExecTracker, FrameIter, NodeOutput, PruneTracker, SetTracker};
22
use simplicity::jet::{Elements, Jet};
33
use simplicity::node::Inner;
4-
use simplicity::{Ihr, RedeemNode, Value as SimValue, ValueRef};
4+
use simplicity::{Ihr, RedeemNode, Value as SimValue};
55

6+
use crate::array::Unfolder;
67
use crate::debug::{DebugSymbols, TrackedCallName};
78
use crate::either::Either;
89
use crate::jet::{source_type, target_type};
@@ -338,43 +339,20 @@ fn parse_jet_arguments(jet: Elements, input_frame: &mut FrameIter) -> Result<Vec
338339
let arguments_blob = SimValue::from_padded_bits(input_frame, &jet.source_ty().to_final())
339340
.expect("input from bit machine is always well-formed");
340341

341-
let mut args = Vec::with_capacity(source_types.len());
342-
collect_product_elements(&arguments_blob.as_ref(), source_types.len(), &mut args)?;
342+
let args = Unfolder::new(arguments_blob.as_ref(), source_types.len())
343+
.unfold(|v| v.as_product())
344+
.ok_or("expected product type while collecting arguments")?;
343345

344346
Ok(args
345347
.into_iter()
346348
.zip(source_types.iter())
347349
.map(|(arg, aliased_type)| {
348-
Value::reconstruct(&arg.into(), &resolve_jet_type(aliased_type))
350+
Value::reconstruct(&arg.to_value().into(), &resolve_jet_type(aliased_type))
349351
.expect("compiled program produces correctly structured values")
350352
})
351353
.collect())
352354
}
353355

354-
/// Recursively collects elements from a nested product type.
355-
///
356-
/// Given a value of type `(A, (B, (C, ...)))`, extracts `[A, B, C, ...]`.
357-
fn collect_product_elements(
358-
node: &ValueRef,
359-
count: usize,
360-
elements: &mut Vec<SimValue>,
361-
) -> Result<(), String> {
362-
match count {
363-
0 => Ok(()),
364-
1 => {
365-
elements.push(node.to_value());
366-
Ok(())
367-
}
368-
_ => {
369-
let (left, right) = node
370-
.as_product()
371-
.ok_or("expected product type while collecting arguments")?;
372-
elements.push(left.to_value());
373-
collect_product_elements(&right, count - 1, elements)
374-
}
375-
}
376-
}
377-
378356
/// Resolves an aliased type to its concrete form.
379357
fn resolve_jet_type(aliased_type: &AliasedType) -> ResolvedType {
380358
aliased_type
@@ -572,4 +550,94 @@ mod tests {
572550
);
573551
assert_eq!(jets.get("eq_64").unwrap().1, Some("true".to_string()));
574552
}
553+
554+
const TEST_FULL_MULTIPLY_JETS: &str = r#"
555+
fn main() {
556+
let r8: u16 = jet::full_multiply_8(200, 201, 202, 203);
557+
let r16: u32 = jet::full_multiply_16(20000, 20001, 20002, 20003);
558+
let r32: u64 = jet::full_multiply_32(2000000000, 2000000001, 2000000002, 2000000003);
559+
let r64: u128 = jet::full_multiply_64(2000000000, 2000000001, 2000000002, 2000000003);
560+
561+
assert!(jet::eq_16(r8, 40605));
562+
assert!(jet::eq_32(r16, 400060005));
563+
assert!(jet::eq_64(r32, 4000000006000000005));
564+
565+
// TODO: Currently no eq_128 jet, this must be revised in future. Placeholder to match on 'unwrap().1`.
566+
let _keep: u128 = r64;
567+
}
568+
"#;
569+
570+
#[test]
571+
fn test_full_multiply_jet_trace_regression() {
572+
// FullMultiply -> (a * b + c + d)
573+
574+
let env = create_test_env();
575+
576+
let program = TemplateProgram::new(TEST_FULL_MULTIPLY_JETS).unwrap();
577+
let program = program.instantiate(Arguments::default(), true).unwrap();
578+
let satisfied = program.satisfy(WitnessValues::default()).unwrap();
579+
580+
let (mut tracker, _, jet_store) = create_test_tracker(&satisfied.debug_symbols);
581+
582+
let _ = satisfied.redeem().prune_with_tracker(&env, &mut tracker);
583+
584+
let jets = jet_store.borrow();
585+
586+
assert_eq!(
587+
jets.get("full_multiply_8").unwrap().0,
588+
Some(vec![
589+
"200".to_string(),
590+
"201".to_string(),
591+
"202".to_string(),
592+
"203".to_string(),
593+
])
594+
);
595+
assert_eq!(
596+
jets.get("full_multiply_8").unwrap().1,
597+
Some("40605".to_string())
598+
);
599+
600+
assert_eq!(
601+
jets.get("full_multiply_16").unwrap().0,
602+
Some(vec![
603+
"20000".to_string(),
604+
"20001".to_string(),
605+
"20002".to_string(),
606+
"20003".to_string(),
607+
])
608+
);
609+
assert_eq!(
610+
jets.get("full_multiply_16").unwrap().1,
611+
Some("400060005".to_string())
612+
);
613+
614+
assert_eq!(
615+
jets.get("full_multiply_32").unwrap().0,
616+
Some(vec![
617+
"2000000000".to_string(),
618+
"2000000001".to_string(),
619+
"2000000002".to_string(),
620+
"2000000003".to_string(),
621+
])
622+
);
623+
assert_eq!(
624+
jets.get("full_multiply_32").unwrap().1,
625+
Some("4000000006000000005".to_string())
626+
);
627+
628+
assert_eq!(
629+
jets.get("full_multiply_64").unwrap().0,
630+
Some(vec![
631+
"2000000000".to_string(),
632+
"2000000001".to_string(),
633+
"2000000002".to_string(),
634+
"2000000003".to_string(),
635+
])
636+
);
637+
assert_eq!(
638+
jets.get("full_multiply_64").unwrap().1,
639+
// Check: u128 defaults to hex in fmt::Display for UIntValue
640+
Some("0x00000000000000003782dad00330bc05".to_string()) // u128 => 4000000006000000005
641+
);
642+
}
575643
}

0 commit comments

Comments
 (0)