@bitcoinerlab/miniscript
Version:
Bitcoin Miniscript, a high-level language for describing Bitcoin spending conditions. It includes a Policy and Miniscript compiler, as well as a novel Satisfier for generating expressive witness scripts.
899 lines (878 loc) • 40.5 kB
JavaScript
import bip68 from 'bip68';
export const primitives = {
0: {
miniscript: '0',
script: '0',
nonMalleableSats: [],
malleableSats: []
},
1: {
miniscript: '1',
script: '1',
throws: 'Miniscript 1 is not sane.'
},
//'pk_k(key)' is not a valid miniscript
'c:pk_k(key)': {
miniscript: 'c:pk_k(key)',
script: '<key> OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key)>' }],
malleableSats: []
},
//same as above
'pk(key)': {
miniscript: 'pk(key)',
script: '<key> OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key)>' }],
malleableSats: []
},
//'pk_h(key)' is not a valid miniscript
'c:pk_h(key)': {
miniscript: 'c:pk_h(key)',
script: 'OP_DUP OP_HASH160 <HASH160(key)> OP_EQUALVERIFY OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key)> <key>' }],
malleableSats: []
},
//same as above
'pkh(key)': {
miniscript: 'pkh(key)',
script: 'OP_DUP OP_HASH160 <HASH160(key)> OP_EQUALVERIFY OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key)> <key>' }],
malleableSats: []
},
//older
'and_v(v:pk(key),older(10))': {
miniscript: 'and_v(v:pk(key),older(10))',
script: '<key> OP_CHECKSIGVERIFY 10 OP_CHECKSEQUENCEVERIFY',
nonMalleableSats: [{ asm: '<sig(key)>', nSequence: 10 }],
malleableSats: []
},
//after
'and_v(v:pk(key),after(10))': {
miniscript: 'and_v(v:pk(key),after(10))',
script: '<key> OP_CHECKSIGVERIFY 10 OP_CHECKLOCKTIMEVERIFY',
nonMalleableSats: [{ asm: '<sig(key)>', nLockTime: 10 }],
malleableSats: []
},
//hashes
'and_v(v:pk(k),sha256(H))': {
miniscript: 'and_v(v:pk(k),sha256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL',
nonMalleableSats: [{ asm: '<sha256_preimage(H)> <sig(k)>' }],
malleableSats: []
},
'with unknowns - and_v(v:pk(k),sha256(H))': {
miniscript: 'and_v(v:pk(k),sha256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL',
unknowns: ['<sha256_preimage(H)>'],
unknownSats: [{ asm: '<sha256_preimage(H)> <sig(k)>' }],
//If the preimage is unknown we cannot compute any satisfaction
nonMalleableSats: [],
malleableSats: []
},
'and_v(v:pk(k),ripemd160(H))': {
miniscript: 'and_v(v:pk(k),ripemd160(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUAL',
nonMalleableSats: [{ asm: '<ripemd160_preimage(H)> <sig(k)>' }],
malleableSats: []
},
'and_v(v:pk(k),hash256(H))': {
miniscript: 'and_v(v:pk(k),hash256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_HASH256 <H> OP_EQUAL',
nonMalleableSats: [{ asm: '<hash256_preimage(H)> <sig(k)>' }],
malleableSats: []
},
'and_v(v:pk(k),hash160(H))': {
miniscript: 'and_v(v:pk(k),hash160(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_HASH160 <H> OP_EQUAL',
nonMalleableSats: [{ asm: '<hash160_preimage(H)> <sig(k)>' }],
malleableSats: []
},
//andor ~truth table
'andor(0,0,0)': {
miniscript: 'andor(0,0,0)',
script: '0 OP_NOTIF 0 OP_ELSE 0 OP_ENDIF',
nonMalleableSats: [],
malleableSats: []
},
'andor(0,0,pk(k))': {
miniscript: 'andor(0,0,pk(k))',
script: '0 OP_NOTIF <k> OP_CHECKSIG OP_ELSE 0 OP_ENDIF',
nonMalleableSats: [{ asm: '<sig(k)>' }],
malleableSats: []
},
'andor(0,pk(k),0)': {
miniscript: 'andor(0,pk(k),0)',
script: '0 OP_NOTIF 0 OP_ELSE <k> OP_CHECKSIG OP_ENDIF',
nonMalleableSats: [],
malleableSats: []
},
'andor(0,pk(key1),pk(key2))': {
miniscript: 'andor(0,pk(key1),pk(key2))',
script: '0 OP_NOTIF <key2> OP_CHECKSIG OP_ELSE <key1> OP_CHECKSIG OP_ENDIF',
nonMalleableSats: [{ asm: '<sig(key2)>' }],
malleableSats: []
},
//other andor(1,Y,Z) combinations are not valid miniscripts
//and_v ~truth table
'and_v(v:0,0)': {
miniscript: 'and_v(v:0,0)',
script: '0 OP_VERIFY 0',
nonMalleableSats: [],
malleableSats: []
},
'and_v(v:0,1)': {
miniscript: 'and_v(v:0,1)',
script: '0 OP_VERIFY 1',
nonMalleableSats: [],
malleableSats: []
},
'and_v(v:1,0)': {
miniscript: 'and_v(v:1,0)',
script: '1 OP_VERIFY 0',
nonMalleableSats: [],
malleableSats: []
},
'and_v(v:pk(key1),pk(key2))': {
miniscript: 'and_v(v:pk(key1),pk(key2))',
script: '<key1> OP_CHECKSIGVERIFY <key2> OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key2)> <sig(key1)>' }],
malleableSats: []
},
//and_b(X,Y): [X] [Y] BOOLAND
'and_b(0,s:pk(key))': {
miniscript: 'and_b(0,s:pk(key))',
script: '0 OP_SWAP <key> OP_CHECKSIG OP_BOOLAND',
nonMalleableSats: [],
malleableSats: []
},
'and_b(1,s:pk(key))': {
miniscript: 'and_b(1,s:pk(key))',
script: '1 OP_SWAP <key> OP_CHECKSIG OP_BOOLAND',
nonMalleableSats: [{ asm: '<sig(key)>' }],
malleableSats: []
},
'and_b(pk(a),s:pk(b))': {
miniscript: 'and_b(pk(a),s:pk(b))',
script: '<a> OP_CHECKSIG OP_SWAP <b> OP_CHECKSIG OP_BOOLAND',
nonMalleableSats: [{ asm: '<sig(b)> <sig(a)>' }],
malleableSats: []
},
//or_b(X,Z) [X] [Z] BOOLOR
'or_b(0,a:0)': {
miniscript: 'or_b(0,a:0)',
script: '0 OP_TOALTSTACK 0 OP_FROMALTSTACK OP_BOOLOR',
nonMalleableSats: [],
malleableSats: []
},
'and_v(v:pk(key1),or_b(pk(key2),a:pk(key3)))': {
miniscript: 'and_v(v:pk(key1),or_b(pk(key2),a:pk(key3)))',
script:
'<key1> OP_CHECKSIGVERIFY <key2> OP_CHECKSIG OP_TOALTSTACK <key3> OP_CHECKSIG OP_FROMALTSTACK OP_BOOLOR',
nonMalleableSats: [
{ asm: '0 <sig(key2)> <sig(key1)>' },
{ asm: '<sig(key3)> 0 <sig(key1)>' }
],
malleableSats: [{ asm: '<sig(key3)> <sig(key2)> <sig(key1)>' }]
},
'and_v(v:pk(key1),or_b(pk(key2),su:after(500000)))': {
miniscript: 'and_v(v:pk(key1),or_b(pk(key2),su:after(500000)))',
script:
'<key1> OP_CHECKSIGVERIFY <key2> OP_CHECKSIG OP_SWAP OP_IF <20a107> OP_CHECKLOCKTIMEVERIFY OP_ELSE 0 OP_ENDIF OP_BOOLOR',
nonMalleableSats: [
{ nLockTime: 500000, asm: '1 0 <sig(key1)>' },
{ asm: '0 <sig(key2)> <sig(key1)>' }
],
malleableSats: [{ nLockTime: 500000, asm: '1 <sig(key2)> <sig(key1)>' }]
},
//or_c(X,Z) [X] NOTIF [Z] ENDIF
't:or_c(0,v:0)': {
miniscript: 't:or_c(0,v:0)',
script: '0 OP_NOTIF 0 OP_VERIFY OP_ENDIF 1',
nonMalleableSats: [],
malleableSats: []
},
//Here we assume that both we and the attacker know ripemd160_preimage.
//In fact, all pre-images are assumed to be publicly known by default.
//If this is the case then we cannot provide this result:
//{"script": "<sig(key2)> <sig(key1)>"}
//Because an attacker could build a new satisfaction using sig(key2)
'c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))': {
miniscript: 'c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))',
script:
'<key1> OP_CHECKSIG OP_NOTIF OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY OP_ENDIF <key2> OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key2)> <ripemd160_preimage(H)> 0' }],
malleableSats: [{ asm: '<sig(key2)> <sig(key1)>' }]
},
//Here we assume that no-one knows ripemd160_preimage.
//The only possible solution is siginig with 2 keys. The attacker cannot
//create a new solution because ripemd160_preimage is not known.
'with unknows set - c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))': {
miniscript: 'c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))',
script:
'<key1> OP_CHECKSIG OP_NOTIF OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY OP_ENDIF <key2> OP_CHECKSIG',
unknowns: ['<ripemd160_preimage(H)>'],
unknownSats: [{ asm: '<sig(key2)> <ripemd160_preimage(H)> 0' }],
nonMalleableSats: [{ asm: '<sig(key2)> <sig(key1)>' }],
malleableSats: []
},
//or_d(X,Z): [X] IFDUP NOTIF [Z] ENDIF
'or_d(0,0)': {
miniscript: 'or_d(0,0)',
script: '0 OP_IFDUP OP_NOTIF 0 OP_ENDIF',
nonMalleableSats: [],
malleableSats: []
},
//solutions are malleable because an attacker can allways default to
//{"nLockTime": 500000, "script": "1 0 0"}
//So nLockTime solution would be the only possible one except this would not
//be sane because it has no signatures.
'or_d(pk(key1),and_b(pk(key2),a:sha256(H)))': {
miniscript: 'or_d(pk(key1),and_b(pk(key2),a:sha256(H)))',
script:
'<key1> OP_CHECKSIG OP_IFDUP OP_NOTIF <key2> OP_CHECKSIG OP_TOALTSTACK OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL OP_FROMALTSTACK OP_BOOLAND OP_ENDIF',
nonMalleableSats: [
{ asm: '<sig(key1)>' },
{ asm: '<sha256_preimage(H)> <sig(key2)> 0' }
],
malleableSats: []
},
//same as above. if don't know sig(key2)
'with unknows set - or_d(pk(key1),and_b(pk(key2),a:sha256(H)))': {
miniscript: 'or_d(pk(key1),and_b(pk(key2),a:sha256(H)))',
script:
'<key1> OP_CHECKSIG OP_IFDUP OP_NOTIF <key2> OP_CHECKSIG OP_TOALTSTACK OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL OP_FROMALTSTACK OP_BOOLAND OP_ENDIF',
unknowns: ['<sig(key2)>'],
//[{"script": "<sig(key1)>"}, {"script": "0 <sig(key2)> 0"}, {"nLockTime": 500000, "script": "1 0 0"}, {"nLockTime": 500000, "script": "1 <sig(key2)> 0"}]
unknownSats: [{ asm: '<sha256_preimage(H)> <sig(key2)> 0' }],
nonMalleableSats: [{ asm: '<sig(key1)>' }],
malleableSats: []
},
'or_d(c:pk_h(key1),andor(c:pk_k(key2),older(2016),pk(key3)))': {
miniscript: 'or_d(c:pk_h(key1),andor(c:pk_k(key2),older(2016),pk(key3)))',
script:
'OP_DUP OP_HASH160 <HASH160(key1)> OP_EQUALVERIFY OP_CHECKSIG OP_IFDUP OP_NOTIF <key2> OP_CHECKSIG OP_NOTIF <key3> OP_CHECKSIG OP_ELSE <e007> OP_CHECKSEQUENCEVERIFY OP_ENDIF OP_ENDIF',
nonMalleableSats: [
{ asm: '<sig(key1)> <key1>' },
{ nSequence: 2016, asm: '<sig(key2)> 0 <key1>' },
{ asm: '<sig(key3)> 0 0 <key1>' }
],
malleableSats: []
},
//or_i(X,Z) IF [X] ELSE [Z] ENDIF
'c:or_i(pk_k(key1),pk_k(key2))': {
miniscript: 'c:or_i(pk_k(key1),pk_k(key2))',
script: 'OP_IF <key1> OP_ELSE <key2> OP_ENDIF OP_CHECKSIG',
nonMalleableSats: [{ asm: '<sig(key1)> 1' }, { asm: '<sig(key2)> 0' }],
malleableSats: []
},
'c:or_i(and_v(v:after(500000),pk_k(key1)),pk_k(key2))': {
miniscript: 'c:or_i(and_v(v:after(500000),pk_k(key1)),pk_k(key2))',
script:
'OP_IF <20a107> OP_CHECKLOCKTIMEVERIFY OP_VERIFY <key1> OP_ELSE <key2> OP_ENDIF OP_CHECKSIG',
nonMalleableSats: [
{ nLockTime: 500000, asm: '<sig(key1)> 1' },
{ asm: '<sig(key2)> 0' }
],
malleableSats: []
},
'with unknowns set - c:or_i(and_v(v:after(500000),pk_k(key1)),pk_k(key2))': {
miniscript: 'c:or_i(and_v(v:after(500000),pk_k(key1)),pk_k(key2))',
script:
'OP_IF <20a107> OP_CHECKLOCKTIMEVERIFY OP_VERIFY <key1> OP_ELSE <key2> OP_ENDIF OP_CHECKSIG',
unknowns: ['<sig(key1)>'],
//If the preimage is not konwn, then it is not malleable.
//[{"nLockTime": 500000, "script": "<sig(key1)> 1"}, {"script": "<sha256_preimage(H)> 0"}]
unknownSats: [{ nLockTime: 500000, asm: '<sig(key1)> 1' }],
nonMalleableSats: [{ asm: '<sig(key2)> 0' }],
malleableSats: []
},
'c:or_i(and_v(v:older(16),pk_h(key1)),pk_h(key2))': {
miniscript: 'c:or_i(and_v(v:older(16),pk_h(key1)),pk_h(key2))',
script:
'OP_IF 16 OP_CHECKSEQUENCEVERIFY OP_VERIFY OP_DUP OP_HASH160 <HASH160(key1)> OP_EQUALVERIFY OP_ELSE OP_DUP OP_HASH160 <HASH160(key2)> OP_EQUALVERIFY OP_ENDIF OP_CHECKSIG',
nonMalleableSats: [
{ nSequence: 16, asm: '<sig(key1)> <key1> 1' },
{ asm: '<sig(key2)> <key2> 0' }
],
malleableSats: []
},
'with unknowns set - c:or_i(and_v(v:older(16),pk_h(key1)),pk_h(key2))': {
miniscript: 'c:or_i(and_v(v:older(16),pk_h(key1)),pk_h(key2))',
script:
'OP_IF 16 OP_CHECKSEQUENCEVERIFY OP_VERIFY OP_DUP OP_HASH160 <HASH160(key1)> OP_EQUALVERIFY OP_ELSE OP_DUP OP_HASH160 <HASH160(key2)> OP_EQUALVERIFY OP_ENDIF OP_CHECKSIG',
unknowns: ['<sig(key1)>', '<sig(key2)>'],
unknownSats: [
{ nSequence: 16, asm: '<sig(key1)> <key1> 1' },
{ asm: '<sig(key2)> <key2> 0' }
],
nonMalleableSats: [],
malleableSats: []
},
'c:or_i(andor(c:pk_h(key1),pk_h(key2),pk_h(key3)),pk_k(key4))': {
miniscript: 'c:or_i(andor(c:pk_h(key1),pk_h(key2),pk_h(key3)),pk_k(key4))',
script:
'OP_IF OP_DUP OP_HASH160 <HASH160(key1)> OP_EQUALVERIFY OP_CHECKSIG OP_NOTIF OP_DUP OP_HASH160 <HASH160(key3)> OP_EQUALVERIFY OP_ELSE OP_DUP OP_HASH160 <HASH160(key2)> OP_EQUALVERIFY OP_ENDIF OP_ELSE <key4> OP_ENDIF OP_CHECKSIG',
nonMalleableSats: [
{ asm: '<sig(key2)> <key2> <sig(key1)> <key1> 1' },
{ asm: '<sig(key3)> <key3> 0 <key1> 1' },
{ asm: '<sig(key4)> 0' }
],
malleableSats: []
},
'or_i(and_b(pk(key1),s:pk(key2)),and_b(older(1),s:pk(key3)))': {
miniscript: 'or_i(and_b(pk(key1),s:pk(key2)),and_b(older(1),s:pk(key3)))',
script:
'OP_IF <key1> OP_CHECKSIG OP_SWAP <key2> OP_CHECKSIG OP_BOOLAND OP_ELSE 1 OP_CHECKSEQUENCEVERIFY OP_SWAP <key3> OP_CHECKSIG OP_BOOLAND OP_ENDIF',
nonMalleableSats: [
{ asm: '<sig(key2)> <sig(key1)> 1' },
{ nSequence: 1, asm: '<sig(key3)> 0' }
],
malleableSats: []
},
'with unknowns set - or_i(and_b(pk(key1),s:pk(key2)),and_b(older(1),s:pk(key3)))':
{
miniscript: 'or_i(and_b(pk(key1),s:pk(key2)),and_b(older(1),s:pk(key3)))',
script:
'OP_IF <key1> OP_CHECKSIG OP_SWAP <key2> OP_CHECKSIG OP_BOOLAND OP_ELSE 1 OP_CHECKSEQUENCEVERIFY OP_SWAP <key3> OP_CHECKSIG OP_BOOLAND OP_ENDIF',
unknowns: ['<sig(key3)>'],
unknownSats: [{ nSequence: 1, asm: '<sig(key3)> 0' }],
nonMalleableSats: [{ asm: '<sig(key2)> <sig(key1)> 1' }],
malleableSats: []
},
//thresh(k,X1,...,Xn) [X1] [X2] ADD ... [Xn] ADD ... <k> EQUAL
'thresh(2,pk(A),s:pk(B),sln:1)': {
miniscript: 'thresh(2,pk(A),s:pk(B),sln:1)',
script:
'<A> OP_CHECKSIG OP_SWAP <B> OP_CHECKSIG OP_ADD OP_SWAP OP_IF 0 OP_ELSE 1 OP_0NOTEQUAL OP_ENDIF OP_ADD 2 OP_EQUAL',
nonMalleableSats: [{ asm: '0 0 <sig(A)>' }, { asm: '0 <sig(B)> 0' }],
malleableSats: [{ asm: '1 <sig(B)> <sig(A)>' }]
},
'with unknownws - thresh(2,pk(A),s:pk(B),sln:1)': {
miniscript: 'thresh(2,pk(A),s:pk(B),sln:1)',
script:
'<A> OP_CHECKSIG OP_SWAP <B> OP_CHECKSIG OP_ADD OP_SWAP OP_IF 0 OP_ELSE 1 OP_0NOTEQUAL OP_ENDIF OP_ADD 2 OP_EQUAL',
unknowns: ['<sig(A)>'],
unknownSats: [{ asm: '0 0 <sig(A)>' }, { asm: '1 <sig(B)> <sig(A)>' }],
nonMalleableSats: [{ asm: '0 <sig(B)> 0' }],
malleableSats: []
},
'with unknowns set - thresh(2,pk(k1),s:pk(k2),sjtv:sha256(H))': {
miniscript: 'thresh(2,pk(k1),s:pk(k2),sjtv:sha256(H))',
script:
'<k1> OP_CHECKSIG OP_SWAP <k2> OP_CHECKSIG OP_ADD OP_SWAP OP_SIZE OP_0NOTEQUAL OP_IF OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUALVERIFY 1 OP_ENDIF OP_ADD 2 OP_EQUAL',
unknowns: ['<sha256_preimage(H)>'],
unknownSats: [
{ asm: '<sha256_preimage(H)> 0 <sig(k1)>' },
{ asm: '<sha256_preimage(H)> <sig(k2)> 0' }
],
nonMalleableSats: [{ asm: '0 <sig(k2)> <sig(k1)>' }],
malleableSats: []
},
'or(thresh(2,pk(k1),pk(k2),sha256(H)),pk(k3))': {
miniscript: 'or(thresh(2,pk(k1),pk(k2),sha256(H)),pk(k3))',
throws:
'Miniscript or(thresh(2,pk(k1),pk(k2),sha256(H)),pk(k3)) is not sane'
},
'thresh(2,multi(2,key1,key2),a:multi(1,key3),ac:pk_k(key4))': {
miniscript: 'thresh(2,multi(2,key1,key2),a:multi(1,key3),ac:pk_k(key4))',
script:
'2 <key1> <key2> 2 OP_CHECKMULTISIG OP_TOALTSTACK 1 <key3> 1 OP_CHECKMULTISIG OP_FROMALTSTACK OP_ADD OP_TOALTSTACK <key4> OP_CHECKSIG OP_FROMALTSTACK OP_ADD 2 OP_EQUAL',
//I manually checked them:
nonMalleableSats: [
{ asm: '0 0 <sig(key3)> 0 <sig(key1)> <sig(key2)>' },
{ asm: '<sig(key4)> 0 0 0 <sig(key1)> <sig(key2)>' },
{ asm: '<sig(key4)> 0 <sig(key3)> 0 0 0' }
],
malleableSats: []
},
'thresh(2,c:pk_h(key),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131))':
{
miniscript:
'thresh(2,c:pk_h(key),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131))',
script:
'OP_DUP OP_HASH160 <HASH160(key1)> OP_EQUALVERIFY OP_CHECKSIG OP_SWAP OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f> OP_EQUAL OP_ADD OP_TOALTSTACK OP_SIZE <20> OP_EQUALVERIFY OP_HASH160 OP_EQUAL OP_FROMALTSTACK OP_ADD 2 OP_EQUAL',
//This is insane because miniscript assumes that preimages are public
//and so 2 of 3 pieces of information would allways be available to
//attackers
//This is not going to work even by setting preimages to unknowns because
//this is expression insane at the miniscript level.
//Read the docs at satisfier(), argument:unknowns, for the details.
throws:
'Miniscript thresh(2,c:pk_h(key),s:sha256(e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f),a:hash160(dd69735817e0e3f6f826a9238dc2e291184f0131)) is not sane.'
},
'thresh(1,c:pk_k(key1),altv:after(1000000000),altv:after(100))': {
miniscript: 'thresh(1,c:pk_k(key1),altv:after(1000000000),altv:after(100))',
//This is insane at the miniscript level because a) it mixes time locks and
//b) because it cannot be satisfyed in a non-malleable: adding any key1
//would satisfy it.
throws:
'Miniscript thresh(1,c:pk_k(key1),altv:after(1000000000),altv:after(100)) is not sane.'
},
'thresh(2,c:pk_k(key1),altv:after(200),altv:after(100))': {
miniscript: 'thresh(2,c:pk_k(key1),altv:after(200),altv:after(100))',
script:
'<key1> OP_CHECKSIG OP_TOALTSTACK OP_IF 0 OP_ELSE <c800> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE <64> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD 2 OP_EQUAL',
//[{"nLockTime": 200, "script": "1 0 <sig(key1)>"}, {"nLockTime": 100, "script": "0 1 <sig(key1)>"}, {"nLockTime": 200, "script": "0 0 0"}]
nonMalleableSats: [{ nLockTime: 200, asm: '0 0 0' }], //Don't reveal the signature
//because it would be malleable
malleableSats: []
},
'thresh(2,c:pk_k(key1),altv:after(200),altv:after(100))': {
miniscript: 'thresh(2,c:pk_k(key1),altv:after(200),altv:after(100))',
script:
'<key1> OP_CHECKSIG OP_TOALTSTACK OP_IF 0 OP_ELSE <c800> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE <64> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD 2 OP_EQUAL',
throws:
'Miniscript thresh(2,c:pk_k(key1),altv:after(200),altv:after(100)) is not sane.'
},
'thresh(2,c:pk_k(key1),ac:pk_k(key2),altv:after(1000000000),altv:after(100))':
{
miniscript:
'thresh(2,c:pk_k(key1),ac:pk_k(key2),altv:after(1000000000),altv:after(100))',
//Same reasoning as above. timelock mic¡xing and any key1 or key2 could satisfy
throws:
'Miniscript thresh(2,c:pk_k(key1),ac:pk_k(key2),altv:after(1000000000),altv:after(100)) is not sane.'
},
'thresh(2,c:pk_k(key1),ac:pk_k(key2),altv:after(100))': {
miniscript: 'thresh(2,c:pk_k(key1),ac:pk_k(key2),altv:after(100))',
//Note that <sig(key1)> or <sig(key2)> in the first solution cannot be
//used to form the other solutions since nLockTime forms part of the
//transaction template whose hash is signed.
// [{"script": "1 <sig(key2)> <sig(key1)>"}, {"nLockTime": 100, "script": "0 0 <sig(key1)>"}, {"nLockTime": 100, "script": "0 <sig(key2)> 0"}]
script:
'<key1> OP_CHECKSIG OP_TOALTSTACK <key2> OP_CHECKSIG OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE <64> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD 2 OP_EQUAL',
nonMalleableSats: [
{ asm: '1 <sig(key2)> <sig(key1)>' },
{ nLockTime: 100, asm: '0 0 <sig(key1)>' },
{ nLockTime: 100, asm: '0 <sig(key2)> 0' }
],
malleableSats: []
},
'thresh(3,c:pk_k(key1),ac:pk_k(key2),altv:after(100),altv:after(200))': {
miniscript:
'thresh(3,c:pk_k(key1),ac:pk_k(key2),altv:after(100),altv:after(200))',
script:
'<key1> OP_CHECKSIG OP_TOALTSTACK <key2> OP_CHECKSIG OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE <64> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE <c800> OP_CHECKLOCKTIMEVERIFY OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD 3 OP_EQUAL',
nonMalleableSats: [
{ nLockTime: 100, asm: '1 0 <sig(key2)> <sig(key1)>' },
//This one below should not be used because it could used to create the
//2 other solutions below by an attacker
//{"nLockTime": 200, "script": "0 1 <sig(key2)> <sig(key1)>"},
{ nLockTime: 200, asm: '0 0 0 <sig(key1)>' },
{ nLockTime: 200, asm: '0 0 <sig(key2)> 0' }
],
malleableSats: [{ nLockTime: 200, asm: '0 1 <sig(key2)> <sig(key1)>' }]
},
'thresh(3,j:and_v(v:ripemd160(H),and_v(v:ripemd160(H),n:older(110))),s:pk(A),s:pk(B),aj:and_v(v:sha256(H),and_v(v:sha256(H),n:older(100))))':
{
miniscript:
'thresh(3,j:and_v(v:ripemd160(H),and_v(v:ripemd160(H),n:older(110))),s:pk(A),s:pk(B),aj:and_v(v:sha256(H),and_v(v:sha256(H),n:older(100))))',
script:
'OP_SIZE OP_0NOTEQUAL OP_IF OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY <6e> OP_CHECKSEQUENCEVERIFY OP_0NOTEQUAL OP_ENDIF OP_SWAP <A> OP_CHECKSIG OP_ADD OP_SWAP <B> OP_CHECKSIG OP_ADD OP_TOALTSTACK OP_SIZE OP_0NOTEQUAL OP_IF OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUALVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUALVERIFY <64> OP_CHECKSEQUENCEVERIFY OP_0NOTEQUAL OP_ENDIF OP_FROMALTSTACK OP_ADD 3 OP_EQUAL',
nonMalleableSats: [
{
nSequence: 110,
asm: '<sha256_preimage(H)> <sha256_preimage(H)> 0 <sig(A)> <ripemd160_preimage(H)> <ripemd160_preimage(H)>'
},
{
nSequence: 110,
asm: '<sha256_preimage(H)> <sha256_preimage(H)> <sig(B)> 0 <ripemd160_preimage(H)> <ripemd160_preimage(H)>'
},
{
nSequence: 100,
asm: '<sha256_preimage(H)> <sha256_preimage(H)> <sig(B)> <sig(A)> 0'
}
],
malleableSats: [
{
nSequence: 110,
asm: '0 <sig(B)> <sig(A)> <ripemd160_preimage(H)> <ripemd160_preimage(H)>'
}
]
},
'with unknowns sats - thresh(3,j:and_v(v:ripemd160(H),and_v(v:ripemd160(H),n:older(110))),s:pk(A),s:pk(B),aj:and_v(v:sha256(H),and_v(v:sha256(H),n:older(100))))':
{
miniscript:
'thresh(3,j:and_v(v:ripemd160(H),and_v(v:ripemd160(H),n:older(110))),s:pk(A),s:pk(B),aj:and_v(v:sha256(H),and_v(v:sha256(H),n:older(100))))',
script:
'OP_SIZE OP_0NOTEQUAL OP_IF OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY <6e> OP_CHECKSEQUENCEVERIFY OP_0NOTEQUAL OP_ENDIF OP_SWAP <A> OP_CHECKSIG OP_ADD OP_SWAP <B> OP_CHECKSIG OP_ADD OP_TOALTSTACK OP_SIZE OP_0NOTEQUAL OP_IF OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUALVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUALVERIFY <64> OP_CHECKSEQUENCEVERIFY OP_0NOTEQUAL OP_ENDIF OP_FROMALTSTACK OP_ADD 3 OP_EQUAL',
unknowns: ['<sha256_preimage(H)>'],
unknownSats: [
{
nSequence: 110,
asm: '<sha256_preimage(H)> <sha256_preimage(H)> 0 <sig(A)> <ripemd160_preimage(H)> <ripemd160_preimage(H)>'
},
{
nSequence: 110,
asm: '<sha256_preimage(H)> <sha256_preimage(H)> <sig(B)> 0 <ripemd160_preimage(H)> <ripemd160_preimage(H)>'
},
{
nSequence: 100,
asm: '<sha256_preimage(H)> <sha256_preimage(H)> <sig(B)> <sig(A)> 0'
}
],
nonMalleableSats: [
{
nSequence: 110,
asm: '0 <sig(B)> <sig(A)> <ripemd160_preimage(H)> <ripemd160_preimage(H)>'
}
],
malleableSats: []
},
'thresh(3,c:pk_k(key1),ac:pk_k(key2),altv:1,altv:1)': {
miniscript: 'thresh(3,c:pk_k(key1),ac:pk_k(key2),altv:1,altv:1)',
script:
'<key1> OP_CHECKSIG OP_TOALTSTACK <key2> OP_CHECKSIG OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE 1 OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_IF 0 OP_ELSE 1 OP_VERIFY 1 OP_ENDIF OP_FROMALTSTACK OP_ADD 3 OP_EQUAL',
nonMalleableSats: [
{ asm: '0 0 0 <sig(key1)>' },
{ asm: '0 0 <sig(key2)> 0' }
],
malleableSats: [
{ asm: '1 0 <sig(key2)> <sig(key1)>' },
{ asm: '0 1 <sig(key2)> <sig(key1)>' }
]
},
//multi(k,key1,...,keyn) -> <k> <key1> ... <keyn> <n> CHECKMULTISIG
'multi(3,key1,key2,key3,key4)': {
miniscript: 'multi(3,key1,key2,key3,key4)',
script: '3 <key1> <key2> <key3> <key4> 4 OP_CHECKMULTISIG',
nonMalleableSats: [
{ asm: '0 <sig(key1)> <sig(key2)> <sig(key3)>' },
{ asm: '0 <sig(key1)> <sig(key2)> <sig(key4)>' },
{ asm: '0 <sig(key1)> <sig(key3)> <sig(key4)>' },
{ asm: '0 <sig(key2)> <sig(key3)> <sig(key4)>' }
],
malleableSats: []
},
'multi(2,key1,key2,key3,key4)': {
miniscript: 'multi(2,key1,key2,key3,key4)',
script: '2 <key1> <key2> <key3> <key4> 4 OP_CHECKMULTISIG',
nonMalleableSats: [
{ asm: '0 <sig(key1)> <sig(key2)>' },
{ asm: '0 <sig(key1)> <sig(key3)>' },
{ asm: '0 <sig(key1)> <sig(key4)>' },
{ asm: '0 <sig(key2)> <sig(key3)>' },
{ asm: '0 <sig(key2)> <sig(key4)>' },
{ asm: '0 <sig(key3)> <sig(key4)>' }
],
malleableSats: []
},
'multi(1,key1,key2)': {
miniscript: 'multi(1,key1,key2)',
script: '1 <key1> <key2> 2 OP_CHECKMULTISIG',
nonMalleableSats: [{ asm: '0 <sig(key1)>' }, { asm: '0 <sig(key2)>' }],
malleableSats: []
},
'multi(0,key1,key2,key3,key4)': {
miniscript: 'multi(0,key1,key2,key3,key4)',
script: '0 <key1> <key2> <key3> <key4> 4 OP_CHECKMULTISIG',
throws: 'Miniscript multi(0,key1,key2,key3,key4) is not sane.'
},
//a:X -> TOALTSTACK [X] FROMALTSTACK -> This has already been tested above.
//s:X -> s:X SWAP [X] -> This has already been tested above.
//c:X -> [X] CHECKSIG -> Tested above.
//d:X -> DUP IF [X] ENDIF
'and_v(v:pk(key),or_d(nd:and_v(v:after(10),v:after(20)),0))': {
miniscript: 'and_v(v:pk(key),or_d(nd:and_v(v:after(10),v:after(20)),0))',
script:
'<key> OP_CHECKSIGVERIFY OP_DUP OP_IF 10 OP_CHECKLOCKTIMEVERIFY OP_VERIFY <14> OP_CHECKLOCKTIMEVERIFY OP_VERIFY OP_ENDIF OP_0NOTEQUAL OP_IFDUP OP_NOTIF 0 OP_ENDIF',
nonMalleableSats: [{ nLockTime: 20, asm: '1 <sig(key)>' }],
malleableSats: []
}
//v:X -> [X] VERIFY (or VERIFY version of last opcode in [X]) -> This has alrady been tested above.
//j:X -> SIZE 0NOTEQUAL IF [X] ENDIF -> This has alrady been tested above.
//n:X -> [X] 0NOTEQUAL -> This has alrady been tested above.
};
export const timeLocks = {
'Sign with key and older than 10 and older than 20 blocks': {
policy: 'and(pk(key),and(older(10),older(20)))',
miniscript: 'and_v(v:pk(key),and_v(v:older(10),older(20)))',
script:
'<key> OP_CHECKSIGVERIFY 10 OP_CHECKSEQUENCEVERIFY OP_VERIFY <14> OP_CHECKSEQUENCEVERIFY',
nonMalleableSats: [{ asm: '<sig(key)>', nSequence: 20 }],
malleableSats: []
},
'(Sign with key1 and older than 10 blocks) or (sign with key2 and older than 20 blocks)':
{
policy: 'or(and(pk(key1),older(10)),and(pk(key2),older(20)))',
miniscript: 'andor(pk(key1),older(10),and_v(v:pk(key2),older(20)))',
script:
'<key1> OP_CHECKSIG OP_NOTIF <key2> OP_CHECKSIGVERIFY <14> OP_CHECKSEQUENCEVERIFY OP_ELSE 10 OP_CHECKSEQUENCEVERIFY OP_ENDIF',
nonMalleableSats: [
{ nSequence: 10, asm: '<sig(key1)>' },
{ nSequence: 20, asm: '<sig(key2)> 0' }
],
malleableSats: []
},
'(Sign with key1 and after than 10 seconds) or (sign with key2 and after than 20 sconds)':
{
policy: 'or(and(pk(key1),after(10)),and(pk(key2),after(20)))',
miniscript: 'andor(pk(key1),after(10),and_v(v:pk(key2),after(20)))',
script:
'<key1> OP_CHECKSIG OP_NOTIF <key2> OP_CHECKSIGVERIFY <14> OP_CHECKLOCKTIMEVERIFY OP_ELSE 10 OP_CHECKLOCKTIMEVERIFY OP_ENDIF',
nonMalleableSats: [
{ asm: '<sig(key1)>', nLockTime: 10 },
{ asm: '<sig(key2)> 0', nLockTime: 20 }
],
malleableSats: []
},
'Throw on mix absolute time locks types. Sign with key and after than 10 and after 500000000':
{
miniscript: 'and_v(v:pk(key),and_v(v:after(10),after(500000000)))',
script:
'<key> OP_CHECKSIGVERIFY 10 OP_CHECKLOCKTIMEVERIFY OP_VERIFY <0065cd1d> OP_CHECKLOCKTIMEVERIFY',
//throws: 'nLockTime values must be either below 500000000 or both above or equal 500000000'
throws:
'Miniscript and_v(v:pk(key),and_v(v:after(10),after(500000000))) is not sane.'
},
['Throw on mix relative time locks types. Sign with key and older than 10 blocks and older than 512 seconds: ' +
`and_v(v:pk(key),and_v(v:older(${bip68.encode({
seconds: 1 * 512
})}),older(${bip68.encode({ blocks: 10 })})))`]: {
miniscript: `and_v(v:pk(key),and_v(v:older(${bip68.encode({
seconds: 1 * 512
})}),older(${bip68.encode({ blocks: 10 })})))`,
//throws: 'a and b must both be either represent seconds or block height'
throws:
'Miniscript and_v(v:pk(key),and_v(v:older(4194305),older(10))) is not sane.'
},
'Do not throw on mix relative time locks types but using different paths. (Sign with key1 and older than 512 seconds) or (sign with key2 and older than 10 blocks)':
{
miniscript: `andor(pk(key1),older(${bip68.encode({
seconds: 1 * 512
})}),and_v(v:pk(key2),older(${bip68.encode({ blocks: 10 })})))`,
script:
'<key1> OP_CHECKSIG OP_NOTIF <key2> OP_CHECKSIGVERIFY 10 OP_CHECKSEQUENCEVERIFY OP_ELSE <010040> OP_CHECKSEQUENCEVERIFY OP_ENDIF',
nonMalleableSats: [
{
asm: '<sig(key1)>',
nSequence: bip68.encode({
seconds: 1 * 512
})
},
{ asm: '<sig(key2)> 0', nSequence: bip68.encode({ blocks: 10 }) }
],
malleableSats: []
},
'and_v(and_v(v:pk(a),v:after(10)),and_v(v:pk(b),after(11)))': {
policy: 'and(and(pk(a),after(10)),and(pk(b),after(11)))',
miniscript: 'and_v(and_v(v:pk(a),v:after(10)),and_v(v:pk(b),after(11)))',
script:
'<a> OP_CHECKSIGVERIFY 10 OP_CHECKLOCKTIMEVERIFY OP_VERIFY <b> OP_CHECKSIGVERIFY 11 OP_CHECKLOCKTIMEVERIFY',
nonMalleableSats: [{ asm: '<sig(b)> <sig(a)>', nLockTime: 11 }],
malleableSats: []
},
'andor(pk(c),after(13),and_v(and_v(v:pk(a),v:after(10)),after(11)))': {
policy: 'or(and(and(pk(a),after(10)),after(11)),and(pk(c),after(13)))',
miniscript:
'andor(pk(c),after(13),and_v(and_v(v:pk(a),v:after(10)),after(11)))',
script:
'<c> OP_CHECKSIG OP_NOTIF <a> OP_CHECKSIGVERIFY 10 OP_CHECKLOCKTIMEVERIFY OP_VERIFY 11 OP_CHECKLOCKTIMEVERIFY OP_ELSE 13 OP_CHECKLOCKTIMEVERIFY OP_ENDIF',
nonMalleableSats: [
{ asm: '<sig(c)>', nLockTime: 13 },
{ asm: '<sig(a)> 0', nLockTime: 11 }
],
malleableSats: []
},
'andor(pk(b),after(100),pk(a))': {
policy: 'or(pk(a),and(pk(b),after(100)))',
miniscript: 'andor(pk(b),after(100),pk(a))',
script:
'<b> OP_CHECKSIG OP_NOTIF <a> OP_CHECKSIG OP_ELSE <64> OP_CHECKLOCKTIMEVERIFY OP_ENDIF',
nonMalleableSats: [
{ asm: '<sig(b)>', nLockTime: 100 },
{ asm: '<sig(a)> 0' }
],
malleableSats: []
}
};
export const other = {
'and_v(v:pk(key_remote),hash160(H))': {
miniscript: 'and_v(v:pk(key_remote),hash160(H))',
nonMalleableSats: [{ asm: '<hash160_preimage(H)> <sig(key_remote)>' }],
script:
'<key_remote> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_HASH160 <H> OP_EQUAL',
malleableSats: []
},
'and_v(v:pk(key),or_b(l:after(100),al:after(200)))': {
miniscript: 'and_v(v:pk(key),or_b(l:after(100),al:after(200)))',
script:
'<key> OP_CHECKSIGVERIFY OP_IF 0 OP_ELSE <64> OP_CHECKLOCKTIMEVERIFY OP_ENDIF OP_TOALTSTACK OP_IF 0 OP_ELSE <c800> OP_CHECKLOCKTIMEVERIFY OP_ENDIF OP_FROMALTSTACK OP_BOOLOR',
throws:
'Miniscript and_v(v:pk(key),or_b(l:after(100),al:after(200))) is not sane.'
},
'and_v(v:pk(key_user),or_d(pk(key_service),older(12960)))': {
miniscript: 'and_v(v:pk(key_user),or_d(pk(key_service),older(12960)))',
script:
'<key_user> OP_CHECKSIGVERIFY <key_service> OP_CHECKSIG OP_IFDUP OP_NOTIF <a032> OP_CHECKSEQUENCEVERIFY OP_ENDIF',
nonMalleableSats: [
{ nSequence: 12960, asm: '0 <sig(key_user)>' },
{ asm: '<sig(key_service)> <sig(key_user)>' }
],
malleableSats: []
},
'andor(pk(matured),older(8640),pk(rushed))': {
miniscript: 'andor(pk(matured),older(8640),pk(rushed))',
script:
'<matured> OP_CHECKSIG OP_NOTIF <rushed> OP_CHECKSIG OP_ELSE <c021> OP_CHECKSEQUENCEVERIFY OP_ENDIF',
nonMalleableSats: [
{ nSequence: 8640, asm: '<sig(matured)>' },
{ asm: '<sig(rushed)> 0' }
],
malleableSats: []
},
'with unknown matured - andor(pk(matured),older(8640),pk(rushed))': {
miniscript: 'andor(pk(matured),older(8640),pk(rushed))',
script:
'<matured> OP_CHECKSIG OP_NOTIF <rushed> OP_CHECKSIG OP_ELSE <c021> OP_CHECKSEQUENCEVERIFY OP_ENDIF',
unknowns: ['<sig(matured)>'],
unknownSats: [{ nSequence: 8640, asm: '<sig(matured)>' }],
nonMalleableSats: [{ asm: '<sig(rushed)> 0' }],
malleableSats: []
},
'with unknown rushed - andor(pk(matured),older(8640),pk(rushed))': {
miniscript: 'andor(pk(matured),older(8640),pk(rushed))',
script:
'<matured> OP_CHECKSIG OP_NOTIF <rushed> OP_CHECKSIG OP_ELSE <c021> OP_CHECKSEQUENCEVERIFY OP_ENDIF',
unknowns: ['<sig(rushed)>'],
unknownSats: [{ asm: '<sig(rushed)> 0' }],
nonMalleableSats: [{ nSequence: 8640, asm: '<sig(matured)>' }],
malleableSats: []
},
'thresh(3,pk(key_1),s:pk(key_2),s:pk(key_3),sln:older(12960))': {
miniscript: 'thresh(3,pk(key_1),s:pk(key_2),s:pk(key_3),sln:older(12960))',
script:
'<key_1> OP_CHECKSIG OP_SWAP <key_2> OP_CHECKSIG OP_ADD OP_SWAP <key_3> OP_CHECKSIG OP_ADD OP_SWAP OP_IF 0 OP_ELSE <a032> OP_CHECKSEQUENCEVERIFY OP_0NOTEQUAL OP_ENDIF OP_ADD 3 OP_EQUAL',
nonMalleableSats: [
{ nSequence: 12960, asm: '0 0 <sig(key_2)> <sig(key_1)>' },
{ nSequence: 12960, asm: '0 <sig(key_3)> 0 <sig(key_1)>' },
{ nSequence: 12960, asm: '0 <sig(key_3)> <sig(key_2)> 0' },
{ asm: '1 <sig(key_3)> <sig(key_2)> <sig(key_1)>' }
],
malleableSats: []
},
'andor(pk(key_local),older(1008),pk(key_revocation))': {
miniscript: 'andor(pk(key_local),older(1008),pk(key_revocation))',
script:
'<key_local> OP_CHECKSIG OP_NOTIF <key_revocation> OP_CHECKSIG OP_ELSE <f003> OP_CHECKSEQUENCEVERIFY OP_ENDIF',
nonMalleableSats: [
{ nSequence: 1008, asm: '<sig(key_local)>' },
{ asm: '<sig(key_revocation)> 0' }
],
malleableSats: []
},
't:or_c(pk(key_revocation),and_v(v:pk(key_remote),or_c(pk(key_local),v:hash160(H))))':
{
miniscript:
't:or_c(pk(key_revocation),and_v(v:pk(key_remote),or_c(pk(key_local),v:hash160(H))))',
script:
'<key_revocation> OP_CHECKSIG OP_NOTIF <key_remote> OP_CHECKSIGVERIFY <key_local> OP_CHECKSIG OP_NOTIF OP_SIZE <20> OP_EQUALVERIFY OP_HASH160 <H> OP_EQUALVERIFY OP_ENDIF OP_ENDIF 1',
nonMalleableSats: [
{ asm: '<sig(key_revocation)>' },
{ asm: '<hash160_preimage(H)> 0 <sig(key_remote)> 0' }
],
malleableSats: [{ asm: '<sig(key_local)> <sig(key_remote)> 0' }]
},
'with unknown preimage - t:or_c(pk(key_revocation),and_v(v:pk(key_remote),or_c(pk(key_local),v:hash160(H))))':
{
miniscript:
't:or_c(pk(key_revocation),and_v(v:pk(key_remote),or_c(pk(key_local),v:hash160(H))))',
script:
'<key_revocation> OP_CHECKSIG OP_NOTIF <key_remote> OP_CHECKSIGVERIFY <key_local> OP_CHECKSIG OP_NOTIF OP_SIZE <20> OP_EQUALVERIFY OP_HASH160 <H> OP_EQUALVERIFY OP_ENDIF OP_ENDIF 1',
unknowns: ['<hash160_preimage(H)>'],
unknownSats: [{ asm: '<hash160_preimage(H)> 0 <sig(key_remote)> 0' }],
nonMalleableSats: [
{ asm: '<sig(key_local)> <sig(key_remote)> 0' },
{ asm: '<sig(key_revocation)>' }
],
malleableSats: []
},
'andor(pk(key_remote),or_i(and_v(v:pkh(key_local),hash160(H)),older(1008)),pk(key_revocation))':
{
miniscript:
'andor(pk(key_remote),or_i(and_v(v:pkh(key_local),hash160(H)),older(1008)),pk(key_revocation))',
script:
'<key_remote> OP_CHECKSIG OP_NOTIF <key_revocation> OP_CHECKSIG OP_ELSE OP_IF OP_DUP OP_HASH160 <HASH160(key_local)> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_HASH160 <H> OP_EQUAL OP_ELSE <f003> OP_CHECKSEQUENCEVERIFY OP_ENDIF OP_ENDIF',
nonMalleableSats: [
{ nSequence: 1008, asm: '0 <sig(key_remote)>' },
{ asm: '<sig(key_revocation)> 0' },
{
asm: '<hash160_preimage(H)> <sig(key_local)> <key_local> 1 <sig(key_remote)>'
}
],
malleableSats: []
},
'thresh(1,pkh(@0),a:and_n(multi(1,@1,@2),n:older(2)))': {
miniscript: 'thresh(1,pkh(@0),a:and_n(multi(1,@1,@2),n:older(2)))',
script:
'OP_DUP OP_HASH160 <HASH160(@0)> OP_EQUALVERIFY OP_CHECKSIG OP_TOALTSTACK 1 <@1> <@2> 2 OP_CHECKMULTISIG OP_NOTIF 0 OP_ELSE 2 OP_CHECKSEQUENCEVERIFY OP_0NOTEQUAL OP_ENDIF OP_FROMALTSTACK OP_ADD 1 OP_EQUAL',
nonMalleableSats: [
{ asm: '0 0 <sig(@0)> <@0>' },
{ asm: '0 <sig(@1)> 0 <@0>', nSequence: 2 },
{ asm: '0 <sig(@2)> 0 <@0>', nSequence: 2 }
],
malleableSats: []
}
};
export const knowns = {
'with unknowns - and_v(v:pk(k),sha256(H))': {
miniscript: 'and_v(v:pk(k),sha256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL',
unknowns: ['<sha256_preimage(H)>'],
unknownSats: [{ asm: '<sha256_preimage(H)> <sig(k)>' }],
//If the preimage is unknown we cannot compute any satisfaction
nonMalleableSats: [],
malleableSats: []
},
'with knowns - and_v(v:pk(k),sha256(H))': {
miniscript: 'and_v(v:pk(k),sha256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL',
knowns: ['<sig(k)>'],
unknownSats: [{ asm: '<sha256_preimage(H)> <sig(k)>' }],
//If the preimage is unknown we cannot compute any satisfaction
nonMalleableSats: [],
malleableSats: []
},
'with all knowns - and_v(v:pk(k),sha256(H))': {
miniscript: 'and_v(v:pk(k),sha256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL',
knowns: ['<sig(k)>', '<sha256_preimage(H)>'],
unknownSats: [],
//If the preimage is unknown we cannot compute any satisfaction
nonMalleableSats: [{ asm: '<sha256_preimage(H)> <sig(k)>' }],
malleableSats: []
},
'throws with both knowns and unknowns - and_v(v:pk(k),sha256(H))': {
miniscript: 'and_v(v:pk(k),sha256(H))',
script:
'<k> OP_CHECKSIGVERIFY OP_SIZE <20> OP_EQUALVERIFY OP_SHA256 <H> OP_EQUAL',
knowns: ['<sig(k)>'],
unknowns: ['<sha256_preimage(H)>'],
throws: 'Cannot pass both knowns and unknowns'
},
'with unknows set - c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))': {
miniscript: 'c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))',
script:
'<key1> OP_CHECKSIG OP_NOTIF OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY OP_ENDIF <key2> OP_CHECKSIG',
unknowns: ['<ripemd160_preimage(H)>'],
unknownSats: [{ asm: '<sig(key2)> <ripemd160_preimage(H)> 0' }],
nonMalleableSats: [{ asm: '<sig(key2)> <sig(key1)>' }],
malleableSats: []
},
'with knows set - c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))': {
miniscript: 'c:and_v(or_c(pk(key1),v:ripemd160(H)),pk_k(key2))',
script:
'<key1> OP_CHECKSIG OP_NOTIF OP_SIZE <20> OP_EQUALVERIFY OP_RIPEMD160 <H> OP_EQUALVERIFY OP_ENDIF <key2> OP_CHECKSIG',
knowns: ['<sig(key1)>', '<sig(key2)>'],
unknownSats: [{ asm: '<sig(key2)> <ripemd160_preimage(H)> 0' }],
nonMalleableSats: [{ asm: '<sig(key2)> <sig(key1)>' }],
malleableSats: []
}
};