Skip to content

Commit 8a9c922

Browse files
committed
feat: Switch to right-associativity
Simfony tuples and arrays are translated into binary trees of Simplicity products. We use BTreeSlice for this conversion. Switch BTreeSlice to produce right-associative binary trees. This resolves many tuple parameters in the signature of jets: fn jet(a: A, bc: (B, C)) becomes fn jet(a: A, b: C, c: C) Most Simplicity jets have right-associative signatures. We have to introduce tuple parameters for jets such as bip_0340_verify which are left-associative. We will add special handling for these jets in a following commit.
1 parent 0c28175 commit 8a9c922

File tree

5 files changed

+48
-35
lines changed

5 files changed

+48
-35
lines changed

example_progs/checksigfromstackverify.simf

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ fn main() {
88
let pk: u256 = 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9;
99
let msg: u256 = witness("msg");
1010
let sig: [u8; 64] = witness("sig");
11-
jet_bip_0340_verify(pk, msg, sig);
11+
jet_bip_0340_verify((pk, msg), sig);
1212
}

example_progs/sighash_all_anyprevoutanyscript.simf

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ fn main() {
2424

2525
let pk: u256 = 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9;
2626
let sig: [u8; 64] = witness("sig");
27-
jet_bip_0340_verify(pk, msg, sig);
27+
jet_bip_0340_verify((pk, msg), sig);
2828
}

example_progs/sighash_none.simf

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ fn main() {
2222

2323
let pk: u256 = 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9;
2424
let sig: [u8; 64] = witness("sig");
25-
jet_bip_0340_verify(pk, msg, sig);
25+
jet_bip_0340_verify((pk, msg), sig);
2626
}

src/array.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use miniscript::iter::{Tree, TreeLike};
55
/// Each node is labelled with a slice.
66
/// Leaves contain single elements.
77
///
8+
/// The tree is right-associative:
9+
/// `&[a b c]` becomes `&[a] (&[b] &[c])`.
10+
///
811
/// The tree is empty if the slice is empty.
912
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1013
pub struct BTreeSlice<'a, A>(&'a [A]);
@@ -57,7 +60,7 @@ impl<'a, A: Clone> TreeLike for BTreeSlice<'a, A> {
5760
let next_pow2 = n.next_power_of_two();
5861
debug_assert!(0 < next_pow2 / 2);
5962
debug_assert!(0 < n - next_pow2 / 2);
60-
let half = next_pow2 / 2;
63+
let half = n - next_pow2 / 2;
6164
let left = BTreeSlice::from_slice(&self.0[..half]);
6265
let right = BTreeSlice::from_slice(&self.0[half..]);
6366
Tree::Binary(left, right)
@@ -195,11 +198,11 @@ mod tests {
195198
(&[], ""),
196199
(&["a"], "a"),
197200
(&["a", "b"], "(ab)"),
198-
(&["a", "b", "c"], "((ab)c)"),
201+
(&["a", "b", "c"], "(a(bc))"),
199202
(&["a", "b", "c", "d"], "((ab)(cd))"),
200-
(&["a", "b", "c", "d", "e"], "(((ab)(cd))e)"),
201-
(&["a", "b", "c", "d", "e", "f"], "(((ab)(cd))(ef))"),
202-
(&["a", "b", "c", "d", "e", "f", "g"], "(((ab)(cd))((ef)g))"),
203+
(&["a", "b", "c", "d", "e"], "(a((bc)(de)))"),
204+
(&["a", "b", "c", "d", "e", "f"], "((ab)((cd)(ef)))"),
205+
(&["a", "b", "c", "d", "e", "f", "g"], "((a(bc))((de)(fg)))"),
203206
(&["a", "b", "c", "d", "e", "f", "g", "h"], "(((ab)(cd))((ef)(gh)))"),
204207
];
205208
let concat = |a: String, b: String| format!("({a}{b})");
@@ -270,10 +273,10 @@ mod tests {
270273
Pattern::array([a.clone(), b.clone()]),
271274
BasePattern::product(a_.clone(), b_.clone()),
272275
),
273-
// [a b c] = ((a, b), c)
276+
// [a b c] = (a, (b, c))
274277
(
275278
Pattern::array([a.clone(), b.clone(), c.clone()]),
276-
BasePattern::product(BasePattern::product(a_.clone(), b_.clone()), c_.clone()),
279+
BasePattern::product(a_.clone(), BasePattern::product(b_.clone(), c_.clone())),
277280
),
278281
// [[a, b], [c, d]] = ((a, b), (c, d))
279282
(

src/jet.rs

+35-25
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,8 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
171171
vec![U64.into(), U64.into()]
172172
}
173173
Elements::Eq256 => vec![U256.into(), U256.into()],
174-
// XXX: nonstandard tuples
175-
Elements::Maj1 | Elements::XorXor1 | Elements::Ch1 => vec![U1.into(), tuple([U1, U1])],
176-
Elements::Maj8 | Elements::XorXor8 | Elements::Ch8 => vec![U8.into(), tuple([U8, U8])],
174+
Elements::Maj1 | Elements::XorXor1 | Elements::Ch1 => vec![U1.into(), U1.into(), U1.into()],
175+
Elements::Maj8 | Elements::XorXor8 | Elements::Ch8 => vec![U8.into(), U8.into(), U8.into()],
177176
Elements::Maj16 | Elements::XorXor16 | Elements::Ch16 => {
178177
vec![U16.into(), tuple([U16, U16])]
179178
}
@@ -219,11 +218,18 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
219218
Elements::FullRightShift64_8 => vec![U8.into(), U64.into()],
220219
Elements::FullRightShift64_16 => vec![U16.into(), U64.into()],
221220
Elements::FullRightShift64_32 => vec![U32.into(), U64.into()],
222-
// XXX: nonstandard tuples
223-
Elements::LeftShiftWith8 | Elements::RightShiftWith8 => vec![U1.into(), tuple([U4, U8])],
224-
Elements::LeftShiftWith16 | Elements::RightShiftWith16 => vec![U1.into(), tuple([U4, U16])],
225-
Elements::LeftShiftWith32 | Elements::RightShiftWith32 => vec![U1.into(), tuple([U8, U32])],
226-
Elements::LeftShiftWith64 | Elements::RightShiftWith64 => vec![U1.into(), tuple([U8, U64])],
221+
Elements::LeftShiftWith8 | Elements::RightShiftWith8 => {
222+
vec![U1.into(), U4.into(), U8.into()]
223+
}
224+
Elements::LeftShiftWith16 | Elements::RightShiftWith16 => {
225+
vec![U1.into(), U4.into(), U16.into()]
226+
}
227+
Elements::LeftShiftWith32 | Elements::RightShiftWith32 => {
228+
vec![U1.into(), U8.into(), U32.into()]
229+
}
230+
Elements::LeftShiftWith64 | Elements::RightShiftWith64 => {
231+
vec![U1.into(), U8.into(), U64.into()]
232+
}
227233
Elements::LeftShift8
228234
| Elements::RightShift8
229235
| Elements::LeftRotate8
@@ -308,10 +314,10 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
308314
| Elements::Divide64
309315
| Elements::Modulo64
310316
| Elements::Divides64 => vec![U64.into(), U64.into()],
311-
Elements::FullAdd8 | Elements::FullSubtract8 => vec![bool(), tuple([U8, U8])],
312-
Elements::FullAdd16 | Elements::FullSubtract16 => vec![bool(), tuple([U16, U16])],
313-
Elements::FullAdd32 | Elements::FullSubtract32 => vec![bool(), tuple([U32, U32])],
314-
Elements::FullAdd64 | Elements::FullSubtract64 => vec![bool(), tuple([U64, U64])],
317+
Elements::FullAdd8 | Elements::FullSubtract8 => vec![bool(), U8.into(), U8.into()],
318+
Elements::FullAdd16 | Elements::FullSubtract16 => vec![bool(), U16.into(), U16.into()],
319+
Elements::FullAdd32 | Elements::FullSubtract32 => vec![bool(), U32.into(), U32.into()],
320+
Elements::FullAdd64 | Elements::FullSubtract64 => vec![bool(), U64.into(), U64.into()],
315321
Elements::FullIncrement8 | Elements::FullDecrement8 => vec![bool(), U8.into()],
316322
Elements::FullIncrement16 | Elements::FullDecrement16 => vec![bool(), U16.into()],
317323
Elements::FullIncrement32 | Elements::FullDecrement32 => vec![bool(), U32.into()],
@@ -320,15 +326,15 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
320326
Elements::FullMultiply16 => vec![tuple([U16, U16]), tuple([U16, U16])],
321327
Elements::FullMultiply32 => vec![tuple([U32, U32]), tuple([U32, U32])],
322328
Elements::FullMultiply64 => vec![tuple([U64, U64]), tuple([U64, U64])],
323-
Elements::Median8 => vec![U8.into(), tuple([U8, U8])],
324-
Elements::Median16 => vec![U16.into(), tuple([U16, U16])],
325-
Elements::Median32 => vec![U32.into(), tuple([U32, U32])],
326-
Elements::Median64 => vec![U64.into(), tuple([U64, U64])],
329+
Elements::Median8 => vec![U8.into(), U8.into(), U8.into()],
330+
Elements::Median16 => vec![U16.into(), U16.into(), U16.into()],
331+
Elements::Median32 => vec![U32.into(), U32.into(), U32.into()],
332+
Elements::Median64 => vec![U64.into(), U64.into(), U64.into()],
327333
/*
328334
* Hash functions
329335
*/
330336
Elements::Sha256Iv | Elements::Sha256Ctx8Init => vec![],
331-
Elements::Sha256Block => vec![U256.into(), tuple([U256, U256])],
337+
Elements::Sha256Block => vec![U256.into(), U256.into(), U256.into()],
332338
Elements::Sha256Ctx8Add1 => vec![Ctx8.into(), U8.into()],
333339
Elements::Sha256Ctx8Add2 => vec![Ctx8.into(), U16.into()],
334340
Elements::Sha256Ctx8Add4 => vec![Ctx8.into(), U32.into()],
@@ -345,11 +351,14 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
345351
* Elliptic curve functions
346352
*/
347353
// XXX: Nonstandard tuple
348-
Elements::PointVerify1 => vec![tuple([Scalar, Point, Scalar]), Point.into()],
354+
Elements::PointVerify1 => {
355+
vec![tuple([tuple([Scalar, Point]), Scalar.into()]), Point.into()]
356+
}
349357
Elements::Decompress => vec![Point.into()],
350358
// XXX: Nonstandard tuple
351-
Elements::LinearVerify1 => vec![tuple([Scalar, Ge, Scalar]), Ge.into()],
352-
Elements::LinearCombination1 => vec![Scalar.into(), Gej.into(), Scalar.into()],
359+
Elements::LinearVerify1 => vec![tuple([tuple([Scalar, Ge]), Scalar.into()]), Ge.into()],
360+
// XXX: Nonstandard tuple
361+
Elements::LinearCombination1 => vec![tuple([Scalar, Gej]), Scalar.into()],
353362
Elements::Scale => vec![Scalar.into(), Gej.into()],
354363
Elements::Generate => vec![Scalar.into()],
355364
Elements::GejInfinity => vec![],
@@ -385,8 +394,10 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
385394
/*
386395
* Digital signatures
387396
*/
388-
Elements::CheckSigVerify => vec![Pubkey.into(), Message64.into(), Signature.into()],
389-
Elements::Bip0340Verify => vec![Pubkey.into(), Message.into(), Signature.into()],
397+
// XXX: Nonstandard tuple
398+
Elements::CheckSigVerify => vec![tuple([Pubkey, Message64]), Signature.into()],
399+
// XXX: Nonstandard tuple
400+
Elements::Bip0340Verify => vec![tuple([Pubkey, Message]), Signature.into()],
390401
/*
391402
* Bitcoin (without primitives)
392403
*/
@@ -422,10 +433,9 @@ pub fn source_type(jet: Elements) -> Vec<AliasedType> {
422433
| Elements::InputScriptsHash
423434
| Elements::TapleafHash
424435
| Elements::TappathHash => vec![],
425-
// XXX: Nonstandard tuples
426-
Elements::OutpointHash => vec![Ctx8.into(), tuple([option(U256), Outpoint.into()])],
436+
Elements::OutpointHash => vec![Ctx8.into(), option(U256), Outpoint.into()],
427437
Elements::AssetAmountHash => {
428-
vec![Ctx8.into(), tuple([Asset1, Amount1])]
438+
vec![Ctx8.into(), Asset1.into(), Amount1.into()]
429439
}
430440
Elements::NonceHash => vec![Ctx8.into(), option(Nonce)],
431441
Elements::AnnexHash => vec![Ctx8.into(), option(U256)],

0 commit comments

Comments
 (0)