Skip to content

Commit eb6b344

Browse files
committed
Always require tapleaf and taproot for TaprootSingleScriptSigInput
1 parent 9b89c87 commit eb6b344

File tree

3 files changed

+50
-132
lines changed

3 files changed

+50
-132
lines changed

coinlib/lib/src/tx/inputs/taproot_single_script_sig_input.dart

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ import 'taproot_script_input.dart';
1414
/// An input that provides a single signature to satisfy a tapscript [leaf].
1515
class TaprootSingleScriptSigInput extends TaprootInput {
1616

17-
final TapLeafChecksig? leaf;
17+
final TapLeafChecksig leaf;
1818
final SchnorrInputSignature? insig;
1919

2020
TaprootSingleScriptSigInput._({
21+
required this.leaf,
22+
required Uint8List controlBlock,
23+
required super.sequence,
2124
OutPoint? prevOut,
22-
this.leaf,
23-
Uint8List? controlBlock,
2425
this.insig,
25-
required super.sequence,
2626
}) : super(
2727
prevOut: prevOut ?? OutPoint.nothing,
2828
witness: [
2929
if (insig != null) insig.bytes,
30-
if (leaf != null) leaf.script.compiled,
31-
if (controlBlock != null) controlBlock,
30+
leaf.script.compiled,
31+
controlBlock,
3232
],
3333
);
3434

@@ -48,13 +48,6 @@ class TaprootSingleScriptSigInput extends TaprootInput {
4848
sequence: sequence,
4949
);
5050

51-
/// Create an APO input with no information that can only be signed with
52-
/// ANYPREVOUTANYSCRIPT.
53-
TaprootSingleScriptSigInput.anyPrevOutAnyScript({
54-
SchnorrInputSignature? insig,
55-
int sequence = Input.sequenceFinal,
56-
}) : this._(insig: insig, sequence: sequence);
57-
5851
/// Create an APO input specifying a [Taproot] and [TapLeaf] that can be
5952
/// signed using ANYPREVOUT or ANYPREVOUTANYSCRIPT. ANYPREVOUTANYSCRIPT may
6053
/// also ommit the taproot information using [anyPrevOutAnyScript()].
@@ -103,23 +96,6 @@ class TaprootSingleScriptSigInput extends TaprootInput {
10396

10497
}
10598

106-
/// Add the [Taproot] and [TapLeaf] required to complete the input for
107-
/// ANYPREVOUTANYSCRIPT. The [prevOut] may optionally be added.
108-
///
109-
/// The signature is not invalidated for ANYPREVOUTANYSCRIPT.
110-
TaprootSingleScriptSigInput addTaproot({
111-
required Taproot taproot,
112-
required TapLeafChecksig leaf,
113-
OutPoint? prevOut,
114-
}) => TaprootSingleScriptSigInput._(
115-
prevOut: prevOut ?? this.prevOut,
116-
leaf: leaf,
117-
controlBlock: taproot.controlBlockForLeaf(leaf),
118-
insig: (insig != null && insig!.hashType.anyPrevOutAnyScript)
119-
? insig : null,
120-
sequence: sequence,
121-
);
122-
12399
/// Complete the input by adding (or replacing) the [OutPoint].
124100
///
125101
/// A signature is not invalidated if ANYPREVOUT or ANYPREVOUTANYSCRIPT is
@@ -129,7 +105,7 @@ class TaprootSingleScriptSigInput extends TaprootInput {
129105
) => TaprootSingleScriptSigInput._(
130106
prevOut: prevOut,
131107
leaf: leaf,
132-
controlBlock: leaf == null ? null : witness.last,
108+
controlBlock: witness.last,
133109
insig: (insig != null && insig!.hashType.requiresApo) ? insig : null,
134110
sequence: sequence,
135111
);
@@ -140,7 +116,7 @@ class TaprootSingleScriptSigInput extends TaprootInput {
140116
) => TaprootSingleScriptSigInput._(
141117
prevOut: prevOut,
142118
leaf: leaf,
143-
controlBlock: leaf == null ? null : witness.last,
119+
controlBlock: witness.last,
144120
insig: insig,
145121
sequence: sequence,
146122
);
@@ -151,17 +127,14 @@ class TaprootSingleScriptSigInput extends TaprootInput {
151127
required ECPrivateKey key,
152128
}) {
153129

154-
if (leaf != null && !leaf!.isApo && details.hashType.requiresApo) {
130+
if (!leaf.isApo && details.hashType.requiresApo) {
155131
throw CannotSignInput(
156132
"Cannot sign with ${details.hashType} for non-APO key",
157133
);
158134
}
159135

160136
return addSignature(
161-
createInputSignature(
162-
key: key,
163-
details: leaf == null ? details : details.addLeafHash(leaf!.hash),
164-
),
137+
createInputSignature(key: key, details: details.addLeafHash(leaf.hash)),
165138
);
166139

167140
}

coinlib/test/tx/inputs/taproot_single_script_sig_input_test.dart

Lines changed: 31 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ final apoTR = Taproot(
1414
internalKey: privkey.pubkey,
1515
mast: TapLeafChecksig.apoInternal,
1616
);
17+
final apoInput = TaprootSingleScriptSigInput.anyPrevOut(
18+
taproot: apoTR,
19+
leaf: TapLeafChecksig.apoInternal,
20+
);
1721
final unsignedTx = Transaction(
1822
inputs: [
1923
TaprootSingleScriptSigInput(
@@ -22,12 +26,8 @@ final unsignedTx = Transaction(
2226
leaf:regularLeaf,
2327
sequence: sequence,
2428
),
25-
TaprootSingleScriptSigInput.anyPrevOut(
26-
taproot: apoTR,
27-
leaf: TapLeafChecksig.apoInternal,
28-
sequence: sequence,
29-
),
30-
TaprootSingleScriptSigInput.anyPrevOutAnyScript(),
29+
apoInput,
30+
apoInput,
3131
],
3232
outputs: [exampleOutput],
3333
);
@@ -44,7 +44,6 @@ void main() {
4444
int i, SigHashType hashType, {
4545
bool addPrevOutBeforeSign = false,
4646
bool addPrevOut = false,
47-
bool addTaproot = false,
4847
}
4948
) {
5049

@@ -69,14 +68,6 @@ void main() {
6968
if (!addPrevOut) return;
7069

7170
input = input.addPrevOut(examplePrevOut);
72-
expect(input.complete, !addTaproot);
73-
74-
if (!addTaproot) return;
75-
76-
input = input.addTaproot(
77-
taproot: apoTR,
78-
leaf: TapLeafChecksig.apoInternal,
79-
);
8071
expect(input.complete, true);
8172

8273
}
@@ -91,89 +82,43 @@ void main() {
9182
expectSign(1, sigHashAOCP, addPrevOutBeforeSign: true);
9283

9384
// APOAS
94-
expectSign(2, sigHashAPOAS, addPrevOut: true, addTaproot: true);
85+
expectSign(2, sigHashAPOAS, addPrevOut: true);
9586

9687
});
9788

98-
test("signatures invalidate on new prevout or tapscript", () {
99-
100-
final altLeaf = TapLeafChecksig.apo(privkey.pubkey);
101-
102-
void expectComplete(
103-
TaprootSingleScriptSigInput input,
104-
bool onPrevOut,
105-
bool onTaproot,
106-
) {
107-
expect(input.complete, true);
108-
expect(input.addPrevOut(exampleAltPrevOut).complete, onPrevOut);
109-
expect(
110-
input.addTaproot(
111-
taproot: Taproot(internalKey: privkey.pubkey, mast: altLeaf),
112-
leaf: altLeaf,
113-
).complete,
114-
onTaproot,
115-
);
116-
}
117-
118-
expectComplete(
119-
TaprootSingleScriptSigInput(
120-
prevOut: examplePrevOut,
121-
taproot: regularTR,
122-
leaf: regularLeaf,
123-
insig: schnorrInSig,
124-
),
125-
false,
126-
false,
127-
);
89+
test("signatures invalidate on new prevout", () {
12890

129-
expectComplete(
130-
TaprootSingleScriptSigInput(
91+
void expectComplete(SchnorrInputSignature inputSig, bool onPrevOut) {
92+
final input = TaprootSingleScriptSigInput(
13193
prevOut: examplePrevOut,
13294
taproot: regularTR,
13395
leaf: regularLeaf,
134-
insig: schnorrInSigAPO,
135-
),
136-
true,
137-
false,
138-
);
139-
140-
expectComplete(
141-
TaprootSingleScriptSigInput(
142-
prevOut: examplePrevOut,
143-
taproot: regularTR,
144-
leaf: regularLeaf,
145-
insig: schnorrInSigAPOAS,
146-
),
147-
true,
148-
true,
149-
);
150-
151-
});
152-
153-
test(".sign() fail", () {
154-
155-
void expectFail(int i, SigHashType hashType) {
156-
final input = unsignedTx.inputs[i] as TaprootSingleScriptSigInput;
157-
expect(
158-
() => input.sign(
159-
details: TaprootScriptSignDetails(
160-
tx: unsignedTx,
161-
inputN: i,
162-
prevOuts: [if (!hashType.anyPrevOutAnyScript) exampleOutput],
163-
hashType: hashType,
164-
),
165-
key: privkey,
166-
),
167-
throwsA(isA<CannotSignInput>()),
96+
insig: inputSig,
16897
);
98+
expect(input.complete, true);
99+
expect(input.addPrevOut(exampleAltPrevOut).complete, onPrevOut);
169100
}
170101

171-
// Signing APO for non-APO key
172-
expectFail(0, sigHashAPO);
102+
expectComplete(schnorrInSig, false);
103+
expectComplete(schnorrInSigAPO, true);
104+
expectComplete(schnorrInSigAPOAS, true);
173105

174-
// Missing leaf for non-APOAS
175-
expectFail(2, sigHashAPO);
106+
});
176107

108+
test(".sign() cannot sign APO for non-APO key", () {
109+
final input = unsignedTx.inputs.first as TaprootSingleScriptSigInput;
110+
expect(
111+
() => input.sign(
112+
details: TaprootScriptSignDetails(
113+
tx: unsignedTx,
114+
inputN: 0,
115+
prevOuts: [exampleOutput],
116+
hashType: sigHashAPO,
117+
),
118+
key: privkey,
119+
),
120+
throwsA(isA<CannotSignInput>()),
121+
);
177122
});
178123

179124
test(".match() success", () {

coinlib/test/tx/transaction_test.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ void main() {
918918
mast: TapLeafChecksig.apoInternal,
919919
);
920920

921+
final apoInput = TaprootSingleScriptSigInput.anyPrevOut(
922+
taproot: taprootApo,
923+
leaf: leafApo,
924+
);
925+
921926
final tx = Transaction(
922927
inputs: [
923928
// Regular SIGHASH_ALL|ANYONECANPAY
@@ -930,12 +935,9 @@ void main() {
930935
leaf: leafRegular,
931936
),
932937
// ANYPREVOUT
933-
TaprootSingleScriptSigInput.anyPrevOut(
934-
taproot: taprootApo,
935-
leaf: leafApo,
936-
),
938+
apoInput,
937939
// ANYPREVOUTANYSCRIPT
938-
TaprootSingleScriptSigInput.anyPrevOutAnyScript(),
940+
apoInput,
939941
// ANYPREVOUT, internal key
940942
TaprootSingleScriptSigInput.anyPrevOut(
941943
taproot: taprootApoInternal,
@@ -985,10 +987,8 @@ void main() {
985987
),
986988
1,
987989
).replaceInput(
988-
(signedTx.inputs[2] as TaprootSingleScriptSigInput).addTaproot(
989-
taproot: taprootApo,
990-
leaf: leafApo,
991-
prevOut: OutPoint.fromHex(
990+
(signedTx.inputs[2] as TaprootSingleScriptSigInput).addPrevOut(
991+
OutPoint.fromHex(
992992
"1bc7c900192ff96e2fbda841f102cf0e924f8614545b16ccf9a89b573d0258f5",
993993
1,
994994
),

0 commit comments

Comments
 (0)