├── .gitattributes
├── .gitignore
├── BitcoinTransactionTool.sln
├── BitcoinTransactionTool
├── App.config
├── App.xaml
├── App.xaml.cs
├── Backend
│ ├── Address.cs
│ ├── Blockchain
│ │ ├── ITransaction.cs
│ │ ├── Outpoint.cs
│ │ ├── Scripts
│ │ │ ├── IPubkeyScript.cs
│ │ │ ├── IRedeemScript.cs
│ │ │ ├── IScript.cs
│ │ │ ├── ISignatureScript.cs
│ │ │ ├── IWitnessScript.cs
│ │ │ ├── OP.cs
│ │ │ ├── Operations
│ │ │ │ ├── ArithmeticOps.cs
│ │ │ │ ├── BaseOperation.cs
│ │ │ │ ├── CheckSigOps.cs
│ │ │ │ ├── CryptoOps.cs
│ │ │ │ ├── EqualityOps.cs
│ │ │ │ ├── FlowControlOps.cs
│ │ │ │ ├── IOpData.cs
│ │ │ │ ├── IOperation.cs
│ │ │ │ ├── LockTimeOps.cs
│ │ │ │ ├── NotRunableOps.cs
│ │ │ │ ├── OpData.cs
│ │ │ │ ├── OpHelper.cs
│ │ │ │ ├── PushDataOp.cs
│ │ │ │ ├── ReturnOp.cs
│ │ │ │ ├── SimpleRunableOps.cs
│ │ │ │ ├── SizeOp.cs
│ │ │ │ ├── StackOps.cs
│ │ │ │ └── VerifyOp.cs
│ │ │ ├── PubkeyScript.cs
│ │ │ ├── RedeemScript.cs
│ │ │ ├── Script.cs
│ │ │ ├── ScriptTypeEnums.cs
│ │ │ ├── SignatureScript.cs
│ │ │ └── WitnessScript.cs
│ │ ├── Transaction.cs
│ │ ├── TxIn.cs
│ │ └── TxOut.cs
│ ├── CompactInt.cs
│ ├── Constants.cs
│ ├── Cryptography
│ │ └── Hashing
│ │ │ ├── IHashFunction.cs
│ │ │ ├── Ripemd160.cs
│ │ │ ├── Ripemd160Sha256.cs
│ │ │ ├── Sha1.cs
│ │ │ └── Sha256.cs
│ ├── Encoders
│ │ ├── Base16.cs
│ │ ├── Base43.cs
│ │ ├── Base58.cs
│ │ └── Bech32.cs
│ ├── ExtentionsAndHelpers.cs
│ ├── IDeserializable.cs
│ ├── JsonConverterHelper.cs
│ ├── LockTime.cs
│ ├── MVVM
│ │ ├── BindableCommand.cs
│ │ ├── DependsOnPropertyAttribute.cs
│ │ ├── InpcBase.cs
│ │ ├── ValidatableBase.cs
│ │ └── ViewModelBase.cs
│ └── StackInt.cs
├── Bitcoin Icon.png.ico
├── BitcoinTransactionTool.csproj
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Models
│ ├── BitcoinAddress.cs
│ ├── ButtonModel.cs
│ ├── PublicKeyModel.cs
│ └── UTXO.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Services
│ ├── Api.cs
│ ├── ErrorCollection.cs
│ ├── OperationConverter.cs
│ ├── PushServices.cs
│ ├── Response.cs
│ ├── ScriptReader.cs
│ ├── ScriptToStringConverter.cs
│ ├── TransactionServices
│ │ ├── BlockCypher.cs
│ │ └── BlockchainInfo.cs
│ ├── TxBuilder.cs
│ └── WindowManager.cs
├── ViewModels
│ ├── MainWindowViewModel.cs
│ ├── QrViewModel.cs
│ ├── ScrAddressViewModel.cs
│ ├── ScrArbitraryDataViewModel.cs
│ ├── ScrHashCollisionViewModel.cs
│ ├── ScrMultiSigViewModel.cs
│ ├── ScriptVMBase.cs
│ ├── ScriptViewModel.cs
│ ├── TransactionEditViewModel.cs
│ └── TxJsonViewModel.cs
├── Views
│ ├── QrView.xaml
│ ├── QrView.xaml.cs
│ ├── ScrAddressView.xaml
│ ├── ScrAddressView.xaml.cs
│ ├── ScrArbitraryDataView.xaml
│ ├── ScrArbitraryDataView.xaml.cs
│ ├── ScrHashCollisionView.xaml
│ ├── ScrHashCollisionView.xaml.cs
│ ├── ScrMultiSigView.xaml
│ ├── ScrMultiSigView.xaml.cs
│ ├── ScriptView.xaml
│ ├── ScriptView.xaml.cs
│ ├── TransactionEditView.xaml
│ ├── TransactionEditView.xaml.cs
│ ├── TxJsonView.xaml
│ └── TxJsonView.xaml.cs
└── packages.config
├── CommonLibrary
├── AsyncCommand.cs
├── AsyncCommandBase.cs
├── BitcoinConversions.cs
├── CommonLibrary.csproj
├── NotifyTaskCompletion.cs
└── Properties
│ └── AssemblyInfo.cs
├── LICENSE
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | bld/
16 | [Bb]in/
17 | [Oo]bj/
18 |
19 | # Roslyn cache directories
20 | *.ide/
21 |
22 | # MSTest test Results
23 | [Tt]est[Rr]esult*/
24 | [Bb]uild[Ll]og.*
25 |
26 | #NUNIT
27 | *.VisualState.xml
28 | TestResult.xml
29 |
30 | # Build Results of an ATL Project
31 | [Dd]ebugPS/
32 | [Rr]eleasePS/
33 | dlldata.c
34 |
35 | *_i.c
36 | *_p.c
37 | *_i.h
38 | *.ilk
39 | *.meta
40 | *.obj
41 | *.pch
42 | *.pdb
43 | *.pgc
44 | *.pgd
45 | *.rsp
46 | *.sbr
47 | *.tlb
48 | *.tli
49 | *.tlh
50 | *.tmp
51 | *.tmp_proj
52 | *.log
53 | *.vspscc
54 | *.vssscc
55 | .builds
56 | *.pidb
57 | *.svclog
58 | *.scc
59 |
60 | # Chutzpah Test files
61 | _Chutzpah*
62 |
63 | # Visual C++ cache files
64 | ipch/
65 | *.aps
66 | *.ncb
67 | *.opensdf
68 | *.sdf
69 | *.cachefile
70 |
71 | # Visual Studio profiler
72 | *.psess
73 | *.vsp
74 | *.vspx
75 |
76 | # TFS 2012 Local Workspace
77 | $tf/
78 |
79 | # Guidance Automation Toolkit
80 | *.gpState
81 |
82 | # ReSharper is a .NET coding add-in
83 | _ReSharper*/
84 | *.[Rr]e[Ss]harper
85 | *.DotSettings.user
86 |
87 | # JustCode is a .NET coding addin-in
88 | .JustCode
89 |
90 | # TeamCity is a build add-in
91 | _TeamCity*
92 |
93 | # DotCover is a Code Coverage Tool
94 | *.dotCover
95 |
96 | # NCrunch
97 | _NCrunch_*
98 | .*crunch*.local.xml
99 |
100 | # MightyMoose
101 | *.mm.*
102 | AutoTest.Net/
103 |
104 | # Web workbench (sass)
105 | .sass-cache/
106 |
107 | # Installshield output folder
108 | [Ee]xpress/
109 |
110 | # DocProject is a documentation generator add-in
111 | DocProject/buildhelp/
112 | DocProject/Help/*.HxT
113 | DocProject/Help/*.HxC
114 | DocProject/Help/*.hhc
115 | DocProject/Help/*.hhk
116 | DocProject/Help/*.hhp
117 | DocProject/Help/Html2
118 | DocProject/Help/html
119 |
120 | # Click-Once directory
121 | publish/
122 |
123 | # Publish Web Output
124 | *.[Pp]ublish.xml
125 | *.azurePubxml
126 | ## TODO: Comment the next line if you want to checkin your
127 | ## web deploy settings but do note that will include unencrypted
128 | ## passwords
129 | #*.pubxml
130 |
131 | # NuGet Packages Directory
132 | packages/*
133 | ## TODO: If the tool you use requires repositories.config
134 | ## uncomment the next line
135 | #!packages/repositories.config
136 |
137 | # Enable "build/" folder in the NuGet Packages folder since
138 | # NuGet packages use it for MSBuild targets.
139 | # This line needs to be after the ignore of the build folder
140 | # (and the packages folder if the line above has been uncommented)
141 | !packages/build/
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | # LightSwitch generated files
187 | GeneratedArtifacts/
188 | _Pvt_Extensions/
189 | ModelManifest.xml
190 | /.vs/
191 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinTransactionTool", "BitcoinTransactionTool\BitcoinTransactionTool.csproj", "{0BD41339-E736-48B1-9BA4-64DB464E954D}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonLibrary", "CommonLibrary\CommonLibrary.csproj", "{3C4402E4-D931-4996-86FB-55FF6F9E7EBD}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/App.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/App.xaml.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System.Windows;
7 | using System.Windows.Threading;
8 |
9 | namespace BitcoinTransactionTool
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
17 | {
18 | MessageBox.Show($"An unhandled catastrophic exception was thrown:\n{e.Exception.Message}",
19 | "Handling Exception in App.xaml", MessageBoxButton.OK, MessageBoxImage.Warning);
20 | e.Handled = true;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/ITransaction.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts;
7 |
8 | namespace BitcoinTransactionTool.Backend.Blockchain
9 | {
10 | public interface ITransaction : IDeserializable
11 | {
12 | TxIn[] TxInList { get; set; }
13 | TxOut[] TxOutList { get; set; }
14 | IWitnessScript[] WitnessList { get; set; }
15 |
16 |
17 | byte[] GetTransactionHash();
18 | //byte[] GetBytesToSign(ITransaction prevTx, int index, SigHashType sigHashType);
19 | //void WriteScriptSig(Signature sig, PublicKey pubKey, ITransaction prevTx, int index);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Outpoint.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 | using System.Linq;
8 |
9 | namespace BitcoinTransactionTool.Backend.Blockchain
10 | {
11 | public class Outpoint : IDeserializable
12 | {
13 | ///
14 | /// Initializes a new instance of using parameters of the .
15 | ///
16 | ///
17 | /// Coin to use
18 | public Outpoint()
19 | {
20 | reverseTxId = true;
21 | HashSize = 32;
22 | Size = sizeof(uint) + HashSize;
23 | }
24 |
25 | ///
26 | /// Initializes a new instance of using given parameters.
27 | ///
28 | ///
29 | ///
30 | /// Hash of the transaction that is being spent as returned by the hash function (no reversal).
31 | /// Index of transaction.
32 | public Outpoint(byte[] hash, uint index)
33 | {
34 | if (hash == null)
35 | throw new ArgumentNullException(nameof(hash), "Transaction hash can not be null.");
36 | if (hash.Length != 32)
37 | throw new ArgumentOutOfRangeException(nameof(hash), $"Transaction hash must be 32 bytes.");
38 |
39 | TxHash = hash.CloneByteArray();
40 | Index = index;
41 |
42 | reverseTxId = true;
43 | HashSize = 32;
44 | Size = sizeof(uint) + HashSize;
45 | }
46 |
47 |
48 |
49 | public byte[] TxHash { get; set; }
50 | public uint Index { get; set; }
51 |
52 | internal readonly int HashSize;
53 | internal readonly int Size;
54 | private readonly bool reverseTxId;
55 |
56 |
57 |
58 | ///
59 | /// Returns transaction ID of this in base-16.
60 | ///
61 | ///
62 | /// Base-16 encoded transaction ID.
63 | public string GetTxId()
64 | {
65 | if (TxHash == null)
66 | throw new ArgumentNullException(nameof(TxHash), "Transaction hash can not be null");
67 |
68 | return reverseTxId ? TxHash.Reverse().ToArray().ToBase16() : TxHash.ToBase16();
69 | }
70 |
71 |
72 | ///
73 | /// Converts this instance into its byte array representation.
74 | ///
75 | ///
76 | /// An array of bytes.
77 | public byte[] Serialize()
78 | {
79 | if (TxHash == null)
80 | throw new ArgumentNullException(nameof(TxHash), "Transaction hash can not be null.");
81 |
82 | return ByteArray.ConcatArrays(
83 | TxHash,
84 | Index.ToByteArray(false)
85 | );
86 | }
87 |
88 |
89 | ///
90 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success.
91 | ///
92 | /// Byte array containing an .
93 | /// The offset inside the to start from.
94 | /// Error message (null if sucessful, otherwise will contain information about the failure).
95 | /// True if deserialization was successful, false if otherwise.
96 | public bool TryDeserialize(byte[] data, ref int offset, out string error)
97 | {
98 | if (offset < 0)
99 | {
100 | error = "Offset can not be negative.";
101 | return false;
102 | }
103 | if (data == null || data.Length - offset < Size)
104 | {
105 | error = "Data length is not valid.";
106 | return false;
107 | }
108 |
109 |
110 | TxHash = data.SubArray(offset, HashSize);
111 | offset += HashSize;
112 |
113 | Index = data.SubArray(offset, sizeof(uint)).ToUInt32(false);
114 | offset += sizeof(uint);
115 |
116 | error = null;
117 | return true;
118 | }
119 |
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/IPubkeyScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
7 | {
8 | public interface IPubkeyScript : IScript
9 | {
10 | ///
11 | /// Returns type of this pubkey script instance.
12 | ///
13 | /// enum
14 | PubkeyScriptType GetPublicScriptType();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/IRedeemScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
7 | {
8 | public interface IRedeemScript : IScript
9 | {
10 | ///
11 | /// Returns type of this redeem script instance.
12 | ///
13 | /// enum
14 | RedeemScriptType GetRedeemScriptType();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/IScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations;
7 |
8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
9 | {
10 | public interface IScript : IDeserializable
11 | {
12 | ///
13 | /// Returns whether the script instance is of witness type. It will affect (de)serialization methods.
14 | ///
15 | bool IsWitness { get; }
16 |
17 | ///
18 | /// Type of this script instance
19 | ///
20 | ScriptType ScriptType { get; }
21 |
22 | ///
23 | /// List of operations that the script contains.
24 | ///
25 | IOperation[] OperationList { get; set; }
26 |
27 | ///
28 | /// Converts this instance into its byte array representation only containing s as bytes
29 | /// without the starting integer for length or count.
30 | ///
31 | /// An array of bytes
32 | byte[] ToByteArray();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/ISignatureScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
7 | {
8 | public interface ISignatureScript : IScript
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/IWitnessScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
7 | {
8 | public interface IWitnessScript : IScript
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/BaseOperation.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Base abstract class for all operations. Implements overrides for Equals() and GetHashCode() functions.
10 | ///
11 | public abstract class BaseOperation : IOperation
12 | {
13 | ///
14 | /// A single byte inticating type of the opeartion
15 | ///
16 | public abstract OP OpValue { get; }
17 |
18 | ///
19 | /// When overriden, performs the specifc operation on the given stack object .
20 | ///
21 | /// Stack to use
22 | /// Error message (null if sucessful, otherwise will contain information about the failure)
23 | /// True if operation was successful, false if otherwise
24 | public abstract bool Run(IOpData opData, out string error);
25 |
26 | ///
27 | /// Determines whether the specified object is equal to the current object.
28 | ///
29 | /// The object to compare with the current object.
30 | /// True if the specified object is equal to the current object, flase if otherwise.
31 | public override bool Equals(object obj)
32 | {
33 | if (obj is IOperation)
34 | {
35 | return ((IOperation)obj).OpValue == OpValue;
36 | }
37 | return false;
38 | }
39 |
40 | ///
41 | /// Returns the hash code for this instance.
42 | ///
43 | /// A 32-bit signed integer hash code
44 | public override int GetHashCode()
45 | {
46 | return OpValue.GetHashCode();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/CheckSigOps.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | public class CheckSigOp : BaseOperation
9 | {
10 | public override OP OpValue => OP.CheckSig;
11 |
12 | public override bool Run(IOpData opData, out string error)
13 | {
14 | if (opData.ItemCount < 2)
15 | {
16 | error = "Invalid number of elements in stack.";
17 | return false;
18 | }
19 |
20 | byte[] pubBa = opData.Pop();
21 | byte[] sigBa = opData.Pop();
22 |
23 | // "fake" pass!
24 | opData.Push(new byte[] { 1 });
25 |
26 | error = null;
27 | return true;
28 | }
29 | }
30 |
31 | public class CheckSigVerifyOp : BaseOperation
32 | {
33 | public override OP OpValue => OP.CheckSigVerify;
34 |
35 | public override bool Run(IOpData opData, out string error)
36 | {
37 | IOperation cs = new CheckSigOp();
38 | IOperation ver = new VerifyOp();
39 |
40 | if (!cs.Run(opData, out error))
41 | {
42 | return false;
43 | }
44 |
45 | return ver.Run(opData, out error);
46 | }
47 | }
48 |
49 | public class CheckMultiSigOp : BaseOperation
50 | {
51 | public override OP OpValue => OP.CheckMultiSig;
52 |
53 | public override bool Run(IOpData opData, out string error)
54 | {
55 | error = null;
56 | return true; // "fake" pass
57 | }
58 | }
59 |
60 | public class CheckMultiSigVerifyOp : BaseOperation
61 | {
62 | public override OP OpValue => OP.CheckMultiSigVerify;
63 |
64 | public override bool Run(IOpData opData, out string error)
65 | {
66 | IOperation cms = new CheckMultiSigOp();
67 | IOperation ver = new VerifyOp();
68 |
69 | if (!cms.Run(opData, out error))
70 | {
71 | return false;
72 | }
73 |
74 | return ver.Run(opData, out error);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/CryptoOps.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Cryptography.Hashing;
7 |
8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
9 | {
10 | ///
11 | /// Base (abstract) class for cryptography operations. Implements and
12 | /// . Derived classes must set the property.
13 | ///
14 | public abstract class CryptoOp : BaseOperation
15 | {
16 | protected abstract IHashFunction Hash { get; }
17 |
18 | ///
19 | /// Replaces top stack item with its hash digest. Return value indicates success.
20 | ///
21 | /// Data to use
22 | /// Error message (null if sucessful, otherwise will contain information about the failure)
23 | /// True if operation was successful, false if otherwise
24 | public override bool Run(IOpData opData, out string error)
25 | {
26 | if (opData.ItemCount < 1)
27 | {
28 | error = "Not enough items in stack.";
29 | return false;
30 | }
31 |
32 | opData.Push(Hash.ComputeHash(opData.Pop()));
33 |
34 | error = null;
35 | return true;
36 | }
37 | }
38 |
39 |
40 |
41 | ///
42 | /// Operation to perform RIPEMD-160 hash on top stack item.
43 | ///
44 | public class RipeMd160Op : CryptoOp
45 | {
46 | public sealed override OP OpValue => OP.RIPEMD160;
47 | protected sealed override IHashFunction Hash => new Ripemd160();
48 | }
49 |
50 |
51 | ///
52 | /// Operation to perform SHA-1 hash on top stack item.
53 | ///
54 | public class Sha1Op : CryptoOp
55 | {
56 | public sealed override OP OpValue => OP.SHA1;
57 | protected sealed override IHashFunction Hash => new Sha1();
58 | }
59 |
60 |
61 | ///
62 | /// Operation to perform SHA-256 hash on top stack item.
63 | ///
64 | public class Sha256Op : CryptoOp
65 | {
66 | public sealed override OP OpValue => OP.SHA256;
67 | protected sealed override IHashFunction Hash => new Sha256(false);
68 | }
69 |
70 |
71 | ///
72 | /// Operation to perform SHA-256 then RIPEMD-160 hash on top stack item.
73 | ///
74 | public class Hash160Op : CryptoOp
75 | {
76 | public sealed override OP OpValue => OP.HASH160;
77 | protected sealed override IHashFunction Hash => new Ripemd160Sha256();
78 | }
79 |
80 |
81 | ///
82 | /// Operation to perform SHA-256 hash twice on top stack item.
83 | ///
84 | public class Hash256Op : CryptoOp
85 | {
86 | public sealed override OP OpValue => OP.HASH256;
87 | protected sealed override IHashFunction Hash => new Sha256(true);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/EqualityOps.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Operation to check equality of top two stack items.
10 | ///
11 | public class EqualOp : BaseOperation
12 | {
13 | public override OP OpValue => OP.EQUAL;
14 |
15 | ///
16 | /// Removes top two stack item and pushes (true for equality and false otherwiwe) onto the stack. Return value indicates success.
17 | ///
18 | /// Data to use
19 | /// Error message (null if sucessful, otherwise will contain information about the failure)
20 | /// True if operation was successful, false if otherwise
21 | public override bool Run(IOpData opData, out string error)
22 | {
23 | if (opData.ItemCount < 2)
24 | {
25 | error = "There was not enough items left in the stack to check.";
26 | return false;
27 | }
28 |
29 | byte[] item1 = opData.Pop();
30 | byte[] item2 = opData.Pop();
31 |
32 | if (item1.IsEqualTo(item2))
33 | {
34 | opData.Push(new byte[] { 1 });
35 | }
36 | else
37 | {
38 | opData.Push(new byte[0]);
39 | }
40 |
41 | error = null;
42 | return true;
43 | }
44 | }
45 |
46 |
47 |
48 | ///
49 | /// Operation to check and verify equality of top two stack items.
50 | ///
51 | public class EqualVerifyOp : BaseOperation
52 | {
53 | public override OP OpValue => OP.EqualVerify;
54 |
55 | ///
56 | /// Removes top two stack item checks their equality, fails if not equal. Return value indicates success.
57 | ///
58 | /// Data to use
59 | /// Error message (null if sucessful, otherwise will contain information about the failure)
60 | /// True if operation was successful, false if otherwise
61 | public override bool Run(IOpData opData, out string error)
62 | {
63 | if (opData.ItemCount < 2)
64 | {
65 | error = "There was not enough items left in the stack to check.";
66 | return false;
67 | }
68 |
69 | byte[] item1 = opData.Pop();
70 | byte[] item2 = opData.Pop();
71 |
72 | if (item1.IsEqualTo(item2))
73 | {
74 | error = null;
75 | return true;
76 | }
77 | else
78 | {
79 | error = "Items were not equal.";
80 | return false;
81 | }
82 |
83 | // ^^ this way we skip unnecessary OP instantiation and Push() and Pop() operations on IOpData
84 |
85 | //EqualOp eq = new EqualOp();
86 | //VerifyOp ver = new VerifyOp();
87 | //if (!eq.Run(opData, out error))
88 | //{
89 | // return false;
90 | //}
91 | //return ver.Run(opData, out error);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/IOpData.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// For implementing a last-in-first-out (LIFO) collection to be used with s.
10 | /// All indexes are zero based meaning item at the end (real index = length-1) is index 0,
11 | /// the item before last is 1,... the first item (real index=0) is length-1.
12 | ///
13 | public interface IOpData
14 | {
15 | //ICoin Coin { get; }
16 |
17 | ///
18 | /// Returns number of available items in the "stack"
19 | ///
20 | int ItemCount { get; }
21 |
22 | ///
23 | /// Returns the item at the top of the "stack" without removing it.
24 | ///
25 | /// The byte array at the top of the stack
26 | byte[] Peek();
27 |
28 | ///
29 | /// Returns multiple items from the top of the "stack" without removing them.
30 | ///
31 | /// Number of items to return
32 | /// An array of byte arrays from the top of the stack
33 | byte[][] Peek(int count);
34 |
35 | ///
36 | /// Returns the item at a specific index starting from the top of the "stack" without removing it.
37 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on.
38 | ///
39 | /// Index of item from end to return (starting from 0)
40 | /// The byte array at the specified intex
41 | byte[] PeekAtIndex(int index);
42 |
43 | ///
44 | /// Removes and returns the item at the top of the "stack".
45 | ///
46 | /// The removed byte array at the top of the stack
47 | byte[] Pop();
48 |
49 | ///
50 | /// Removes multiple items from the top of the stack and returns all of them without changing the order ([1234] -> [34]).
51 | ///
52 | /// Number of items to remove and return
53 | /// An array of byte arrays removed from the top of the stack
54 | byte[][] Pop(int count);
55 |
56 | ///
57 | /// Removes and returns the item at the specified index (will shift the items in its place).
58 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on.
59 | ///
60 | ///
61 | /// The byte array removed from the specified intex
62 | byte[] PopAtIndex(int index);
63 |
64 | ///
65 | /// Pushes (or inserts) an item at the top of the "stack".
66 | ///
67 | /// Byte array to push onto the "stack"
68 | void Push(byte[] data);
69 |
70 | ///
71 | /// Pushes (or inserts) multiple items at the top of the "stack" in the same order.
72 | ///
73 | /// Arrays of byte array to push
74 | void Push(byte[][] data);
75 |
76 | ///
77 | /// Inserts an item at the specified index (from the top) of the "stack".
78 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on.
79 | ///
80 | /// Byte array to insert in the "stack"
81 | /// Index at which to insert the
82 | void Insert(byte[] data, int index);
83 |
84 | ///
85 | /// Inserts multiple items at the specified index (from the top) of the "stack".
86 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on.
87 | ///
88 | /// Array of Byte arrays to insert in the "stack"
89 | /// Index at which to insert the
90 | void Insert(byte[][] data, int index);
91 |
92 |
93 | ///
94 | /// Returns number of available items in the "alt-stack"
95 | ///
96 | int AltItemCount { get; }
97 |
98 | ///
99 | /// Removes and returns the item at the top of the "alt-stack".
100 | ///
101 | /// The removed byte array at the top of the "alt-stack"
102 | byte[] AltPop();
103 |
104 | ///
105 | /// Pushes (or inserts) an item at the top of the "alt-stack".
106 | ///
107 | /// Byte array to push onto the "alt-stack"
108 | void AltPush(byte[] data);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/IOperation.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Defines any kind of operation that is placed inside s and could be run.
10 | ///
11 | public interface IOperation
12 | {
13 | ///
14 | /// A single byte inticating type of the opeartion
15 | ///
16 | OP OpValue { get; }
17 |
18 | ///
19 | /// Performs the action defined by the operation on the stack. Return value indicates success.
20 | ///
21 | /// Data used by the s (an advanced form of )
22 | /// Error message (null if sucessful, otherwise will contain information about the failure)
23 | /// True if operation was successful, false if otherwise
24 | bool Run(IOpData opData, out string error);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/LockTimeOps.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | public abstract class LockTimeOp : BaseOperation
9 | {
10 | ///
11 | /// The locktime value converted from the top stack item (without popping it)
12 | ///
13 | protected long lt;
14 |
15 | protected bool TrySetLockTime(IOpData opData, out string error)
16 | {
17 | if (opData.ItemCount < 1)
18 | {
19 | error = "Not enough items left in the stack.";
20 | return false;
21 | }
22 |
23 | // The two locktime OPs (CheckLocktimeVerify and CheckSequenceVerify) used to be NOPs. NOPs don't do anything.
24 | // For backward compatibility of the softfork, Run Peeks at the top item of the stack instead of Poping it.
25 | byte[] data = opData.Peek();
26 |
27 | // TODO: move this check to OpHelper
28 | // (for locktimes max length is 5 for others it is 4)
29 | if (data.Length > 5)
30 | {
31 | error = "Data length for locktimes can not be bigger than 5.";
32 | return false;
33 | }
34 |
35 | if (!OpHelper.TryConvertByteArrayToInt(data, out lt, true))
36 | {
37 | error = "Invalid number format.";
38 | return false;
39 | }
40 |
41 | if (lt < 0)
42 | {
43 | error = "Locktime can not be negative.";
44 | return false;
45 | }
46 |
47 | error = null;
48 | return true;
49 | }
50 | }
51 |
52 |
53 |
54 | public class CheckLocktimeVerifyOp : LockTimeOp
55 | {
56 | public override OP OpValue => OP.CheckLocktimeVerify;
57 |
58 | public override bool Run(IOpData opData, out string error)
59 | {
60 | if (!TrySetLockTime(opData, out error))
61 | {
62 | return false;
63 | }
64 |
65 | // Compare to tx.locktime (we assume it is valid and skip this!)
66 | // TODO: change this for this tool if transactions were set inside IOpdata one day...
67 |
68 | error = null;
69 | return true;
70 | }
71 | }
72 |
73 |
74 |
75 | public class CheckSequenceVerifyOp : LockTimeOp
76 | {
77 | public override OP OpValue => OP.CheckSequenceVerify;
78 |
79 | public override bool Run(IOpData opData, out string error)
80 | {
81 | if (!TrySetLockTime(opData, out error))
82 | {
83 | return false;
84 | }
85 |
86 | // Compare to tx.locktime, as relative locktime (we assume it is valid and skip this!)
87 | // TODO: change this for this tool if transactions were set inside IOpdata one day...
88 |
89 | error = null;
90 | return true;
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/NotRunableOps.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Base abstract class for operations that can not be run
10 | /// (should fail when is called).
11 | /// Implements a finalized Run() and has overrides for Equals() and GetHashCode() functions from class.
12 | ///
13 | public abstract class NotRunableOps : BaseOperation
14 | {
15 | ///
16 | /// Fails when called.
17 | ///
18 | /// Stack object (won't be used)
19 | /// Error message (contains name of the operation that caused the failure)
20 | /// False (always failing)
21 | public sealed override bool Run(IOpData opData, out string error)
22 | {
23 | error = $"Can not run an OP_{OpValue.ToString()} operation.";
24 | return false;
25 | }
26 | }
27 |
28 |
29 |
30 | // We have an IOperation for OP.Reserved,... because they can exist in a transaction but can not be run.
31 | // We don't have any IOperation for OP.VerIf,... because they can neither exist nor be run.
32 |
33 |
34 | ///
35 | /// Reserved operation, will fail on running.
36 | ///
37 | public class ReservedOp : NotRunableOps
38 | {
39 | public override OP OpValue => OP.Reserved;
40 | }
41 |
42 | ///
43 | /// Removed operation, will fail on running.
44 | ///
45 | public class VEROp : NotRunableOps
46 | {
47 | public override OP OpValue => OP.VER;
48 | }
49 |
50 | ///
51 | /// Reserved operation, will fail on running.
52 | ///
53 | public class Reserved1Op : NotRunableOps
54 | {
55 | public override OP OpValue => OP.Reserved1;
56 | }
57 |
58 | ///
59 | /// Reserved operation, will fail on running.
60 | ///
61 | public class Reserved2Op : NotRunableOps
62 | {
63 | public override OP OpValue => OP.Reserved2;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/OpHelper.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 |
8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
9 | {
10 | internal static class OpHelper
11 | {
12 | ///
13 | /// Checks whether a given byte array is zero (...,0,0,0,0) or negative zero (...,0,0,0x80)
14 | /// This is the same as IsTrue()
15 | ///
16 | /// Byte array to check
17 | /// True if given bytes represented zero or negative zero; False if otherwise.
18 | internal static bool IsNotZero(byte[] data)
19 | {
20 | for (int i = 0; i < data.Length; i++)
21 | {
22 | if (data[i] != 0)
23 | {
24 | // Can be negative zero
25 | if (i == data.Length - 1 && data[i] == 0x80)
26 | {
27 | return false;
28 | }
29 | return true;
30 | }
31 | }
32 | return false;
33 | }
34 |
35 |
36 | // This method is supposed to convert the bytes that are already in the stack (not in scripts) to a numeric value.
37 | // This method is called by the following methods and each require a specific size of data:
38 | // - ArithmeticOps that need values between(-2^31 +1) and(2^31 -1) (0xffffff7f) => 4 bytes
39 | // - Multisig m of n that needs values between 0 and 20 => 1 byte
40 | // - Locktimes that need values between 0 and(2^39-1) (0xffffffff7f) => 5 bytes
41 | //
42 | // So we choose the biggest type we have(Int64) but the caller is responsible to check if returned value is in range or not.
43 | //
44 | // IsStrict is only there to ensure shortest form was chosen to encode a number: 1 = {1} instead of {1,0,0}
45 | public static bool TryConvertByteArrayToInt(byte[] data, out long result, bool isStrict)
46 | {
47 | result = 0;
48 | if (data == null || data.Length > sizeof(long))
49 | {
50 | return false;
51 | }
52 |
53 | if (data.Length == 0)
54 | {
55 | return true;
56 | }
57 |
58 | if (isStrict && (data[data.Length - 1] & 0b0111_1111) == 0)
59 | {
60 | if (data.Length <= 1 || (data[data.Length - 2] & 0b1000_0000) == 0)
61 | {
62 | return false;
63 | }
64 | }
65 |
66 | for (int i = 0; i < data.Length; i++)
67 | {
68 | result |= (long)data[i] << (8 * i);
69 | }
70 |
71 | if ((data[data.Length - 1] & 0b1000_0000) != 0)
72 | {
73 | result &= ~(0b1000_0000 << (8 * (data.Length - 1)));
74 | result *= -1;
75 | }
76 |
77 | return true;
78 | }
79 |
80 |
81 | public static byte[] IntToByteArray(long val)
82 | {
83 | if (val == 0)
84 | {
85 | return new byte[0];
86 | }
87 |
88 | if (val >= 0)
89 | {
90 | byte[] data = val.ToByteArray(false).TrimEnd();
91 | if ((data[data.Length - 1] & 0b1000_0000) != 0)
92 | {
93 | data = data.AppendToEnd(0);
94 | }
95 | return data;
96 | }
97 | else
98 | {
99 | byte[] data = (-val).ToByteArray(false).TrimEnd();
100 | if ((data[data.Length - 1] & 0b1000_0000) == 0)
101 | {
102 | data[data.Length - 1] |= 0b1000_0000;
103 | }
104 | else
105 | {
106 | data = data.AppendToEnd(0b1000_0000);
107 | }
108 | return data;
109 | }
110 | }
111 |
112 |
113 | internal static OP IntToOp(int val)
114 | {
115 | if (val == 0)
116 | {
117 | return OP._0;
118 | }
119 | else if (val == -1)
120 | {
121 | return OP.Negative1;
122 | }
123 | else if (val >= 1 && val <= 16)
124 | {
125 | // OP_1 = 0x51, OP_2 = 0x52,...
126 | return (OP)(val + 0x50);
127 | }
128 | else
129 | {
130 | throw new ArgumentOutOfRangeException(nameof(val), "There is no OP defined for values outside of ∈[-1,16].");
131 | }
132 | }
133 |
134 |
135 | public static bool HasOpNum(byte[] data)
136 | {
137 | if (data.Length == 0)
138 | {
139 | return true;
140 | }
141 | else if (data.Length == 1)
142 | {
143 | if (data[0] == 0b10000000 /*-1*/ || data[0] >= 0 && data[0] <= 16)
144 | {
145 | return true;
146 | }
147 | }
148 |
149 | return false;
150 | }
151 |
152 | internal static bool IsNumberOp(OP val)
153 | {
154 | return !(val != OP._0 && val != OP.Negative1 && val < OP._1 || val > OP._16);
155 | }
156 |
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/ReturnOp.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 |
8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
9 | {
10 | ///
11 | /// Operation that is used to include an arbitrary data in transactions, it will fail on running.
12 | ///
13 | public class ReturnOp : NotRunableOps
14 | {
15 | ///
16 | /// Initializes a new instance of with an empty data (0x6a).
17 | ///
18 | public ReturnOp()
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of using the given data.
24 | ///
25 | /// Data to use (can be null)
26 | ///
27 | /// [Default value = true]
28 | /// If true, the data will be included after using scheme.
29 | ///
30 | public ReturnOp(byte[] ba, bool usePushOp = true)
31 | {
32 | if (ba == null || ba.Length == 0)
33 | {
34 | Data = new byte[1] { (byte)OP.RETURN };
35 | }
36 | else if (usePushOp)
37 | {
38 | StackInt size = new StackInt(ba.Length);
39 | Data = ByteArray.ConcatArrays(
40 | new byte[1] { (byte)OP.RETURN },
41 | size.ToByteArray(),
42 | ba);
43 | }
44 | else
45 | {
46 | Data = new byte[ba.Length + 1];
47 | Data[0] = (byte)OP.RETURN;
48 | Buffer.BlockCopy(ba, 0, Data, 1, ba.Length);
49 | }
50 | }
51 |
52 | ///
53 | /// Initializes a new instance of using the given .
54 | ///
55 | ///
56 | /// Script to use
57 | ///
58 | /// [Default value = true]
59 | /// If true, the data will be included after using scheme.
60 | ///
61 | public ReturnOp(IScript scr, bool usePushOp = true)
62 | {
63 | if (scr == null)
64 | throw new ArgumentNullException(nameof(scr), "Script can not be null.");
65 |
66 | byte[] temp = scr.ToByteArray();
67 |
68 | if (usePushOp)
69 | {
70 | StackInt size = new StackInt(temp.Length);
71 | Data = ByteArray.ConcatArrays(
72 | new byte[1] { (byte)OP.RETURN },
73 | size.ToByteArray(),
74 | temp);
75 | }
76 | else
77 | {
78 | Data = new byte[temp.Length + 1];
79 | Data[0] = (byte)OP.RETURN;
80 | Buffer.BlockCopy(temp, 0, Data, 1, temp.Length);
81 | }
82 | }
83 |
84 |
85 |
86 | // TODO: change accessibility to internal and let test project access it only
87 | public byte[] Data { get; private set; }
88 |
89 | ///
90 | /// A single byte inticating type of the opeartion
91 | ///
92 | public override OP OpValue => OP.RETURN;
93 |
94 |
95 |
96 | ///
97 | /// Returns the byte array representation of this operation based on its type and data.
98 | /// Used by Serialize() methods.
99 | ///
100 | /// An array of bytes
101 | public byte[] ToByteArray()
102 | {
103 | if (Data == null || Data.Length == 0)
104 | {
105 | return new byte[1] { (byte)OP.RETURN };
106 | }
107 | else
108 | {
109 | return Data.CloneByteArray();
110 | }
111 | }
112 |
113 |
114 | ///
115 | /// Reads the byte and the following specified data length from the specified offset.
116 | /// The return value indicates success.
117 | ///
118 | /// Byte array to use
119 | /// The offset inside the to start from.
120 | /// Error message (null if sucessful, otherwise will contain information about the failure).
121 | ///
122 | /// Length of the data to read. Must be at least 1 byte, the itself.
123 | /// (note that doesn't have any internal mechanism to tell us how much data it holds,
124 | /// the length is instead specified before as the length of the whole script).
125 | ///
126 | /// True if reading was successful, false if otherwise.
127 | public bool TryRead(byte[] data, ref int offset, out string error, int length)
128 | {
129 | if (offset < 0)
130 | {
131 | error = "Offset can not be negative.";
132 | return false;
133 | }
134 | if (length < 1)
135 | {
136 | error = "Lengh can not be smaller than 1.";
137 | return false;
138 | }
139 | if (data == null || data.Length - offset < length)
140 | {
141 | error = "Data length is not valid.";
142 | return false;
143 | }
144 | if (data[offset] != (byte)OP.RETURN)
145 | {
146 | error = $"OP at offset={offset} is not equal to OP_Return.";
147 | return false;
148 | }
149 |
150 | Data = data.SubArray(offset, length);
151 | offset += length;
152 |
153 | error = null;
154 | return true;
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/SimpleRunableOps.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Base abstract class for operations that don't do anything with the stack.
10 | /// Implements a finalized Run() and has overrides for Equals() and GetHashCode() functions from class.
11 | ///
12 | public abstract class SimpleRunableOps : BaseOperation
13 | {
14 | ///
15 | /// Doesn't do anything.
16 | ///
17 | /// Stack object (won't be used)
18 | /// Error message (always null)
19 | /// True (always successful)
20 | public sealed override bool Run(IOpData opData, out string error)
21 | {
22 | error = null;
23 | return true;
24 | }
25 | }
26 |
27 |
28 |
29 | ///
30 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
31 | ///
32 | public class NOPOp : SimpleRunableOps
33 | {
34 | public override OP OpValue => OP.NOP;
35 | }
36 |
37 | ///
38 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
39 | ///
40 | public class NOP1Op : SimpleRunableOps
41 | {
42 | public override OP OpValue => OP.NOP1;
43 | }
44 |
45 | ///
46 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
47 | ///
48 | public class NOP4Op : SimpleRunableOps
49 | {
50 | public override OP OpValue => OP.NOP4;
51 | }
52 |
53 | ///
54 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
55 | ///
56 | public class NOP5Op : SimpleRunableOps
57 | {
58 | public override OP OpValue => OP.NOP5;
59 | }
60 |
61 | ///
62 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
63 | ///
64 | public class NOP6Op : SimpleRunableOps
65 | {
66 | public override OP OpValue => OP.NOP6;
67 | }
68 |
69 | ///
70 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
71 | ///
72 | public class NOP7Op : SimpleRunableOps
73 | {
74 | public override OP OpValue => OP.NOP7;
75 | }
76 |
77 | ///
78 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
79 | ///
80 | public class NOP8Op : SimpleRunableOps
81 | {
82 | public override OP OpValue => OP.NOP8;
83 | }
84 |
85 | ///
86 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
87 | ///
88 | public class NOP9Op : SimpleRunableOps
89 | {
90 | public override OP OpValue => OP.NOP9;
91 | }
92 |
93 | ///
94 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks.
95 | ///
96 | public class NOP10Op : SimpleRunableOps
97 | {
98 | public override OP OpValue => OP.NOP10;
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/SizeOp.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Operation to push the size of the top stack item to the stack.
10 | ///
11 | public class SizeOp : IOperation
12 | {
13 | public OP OpValue => OP.SIZE;
14 |
15 | ///
16 | /// Pushes the size of the top stack item to the stack. Return value indicates success.
17 | ///
18 | /// Data to use
19 | /// Error message (null if sucessful, otherwise will contain information about the failure)
20 | /// True if operation was successful, false if otherwise
21 | public bool Run(IOpData opData, out string error)
22 | {
23 | if (opData.ItemCount < 1)
24 | {
25 | error = "There was not enough items left in the stack.";
26 | return false;
27 | }
28 |
29 | byte[] temp = opData.Peek();
30 | opData.Push(OpHelper.IntToByteArray(temp.Length));
31 |
32 | error = null;
33 | return true;
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/VerifyOp.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations
7 | {
8 | ///
9 | /// Operation to verify if the top stack item is true.
10 | ///
11 | public class VerifyOp : BaseOperation
12 | {
13 | public override OP OpValue => OP.VERIFY;
14 |
15 | ///
16 | /// Removes top stack item only passes if it is true. Return value indicates success.
17 | ///
18 | /// Data to use
19 | /// Error message (null if sucessful, otherwise will contain information about the failure)
20 | /// True if operation was successful, false if otherwise
21 | public override bool Run(IOpData opData, out string error)
22 | {
23 | if (opData.ItemCount < 1)
24 | {
25 | error = "There was not enough items left in the stack.";
26 | return false;
27 | }
28 | // Check the top stack value, only fail if False
29 | bool b = OpHelper.IsNotZero(opData.Pop());
30 | if (!b)
31 | {
32 | error = "Top stack item value was 'false'.";
33 | return false;
34 | }
35 |
36 | error = null;
37 | return true;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/RedeemScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations;
7 | using BitcoinTransactionTool.Backend.Cryptography.Hashing;
8 | using System;
9 |
10 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
11 | {
12 | public class RedeemScript : Script, IRedeemScript
13 | {
14 | public RedeemScript()
15 | {
16 | IsWitness = false;
17 | OperationList = new IOperation[0];
18 | ScriptType = ScriptType.ScriptRedeem;
19 | hashFunc = new Ripemd160Sha256() /*coin.AddressHashFunction*/;
20 |
21 | witHashFunc = new Sha256(false); // TODO: set this field in ICoin
22 | maxLenOrCount = 10000; // TODO: set this to a real value and from ICoin
23 | }
24 |
25 |
26 |
27 | private IHashFunction hashFunc;
28 | private IHashFunction witHashFunc;
29 |
30 |
31 |
32 | public RedeemScriptType GetRedeemScriptType()
33 | {
34 | if (OperationList == null || OperationList.Length == 0)
35 | {
36 | return RedeemScriptType.Empty;
37 | }
38 | else if (OperationList.Length == 2 &&
39 | OperationList[0] is PushDataOp && OperationList[0].OpValue == OP._0 &&
40 | OperationList[1] is PushDataOp && ((PushDataOp)OperationList[1]).data.Length == hashFunc.HashByteSize)
41 | {
42 | return RedeemScriptType.P2SH_P2WPKH;
43 | }
44 | else if (OperationList.Length == 2 &&
45 | OperationList[0] is PushDataOp && OperationList[0].OpValue == OP._0 &&
46 | OperationList[1] is PushDataOp && ((PushDataOp)OperationList[1]).data.Length == witHashFunc.HashByteSize)
47 | {
48 | return RedeemScriptType.P2SH_P2WSH;
49 | }
50 |
51 | return RedeemScriptType.Unknown;
52 | }
53 |
54 | //public void SetToMultiSig(int m, int n, Tuple[] pubKeyList)
55 | //{
56 | // if (m < 1 || m > 16 || m > n)
57 | // throw new ArgumentOutOfRangeException(nameof(m), "M must be between 1 and 16 and smaller than N.");
58 | // if (n < 1 || n > 16)
59 | // throw new ArgumentOutOfRangeException(nameof(n), "N must be between 1 and 16.");
60 | // if (pubKeyList == null || pubKeyList.Length == 0)
61 | // throw new ArgumentNullException(nameof(pubKeyList), "Pubkey list can not be null or empty.");
62 | // if (pubKeyList.Length != n)
63 | // throw new ArgumentOutOfRangeException(nameof(pubKeyList), $"Pubkey list must contain N (={n}) items.");
64 |
65 | // OperationList = new IOperation[n + 3]; // OP_m | pub1 | pub2 | ... | pub(n) | OP_n | OP_CheckMultiSig
66 | // OperationList[0] = new PushDataOp(m);
67 | // OperationList[n + 1] = new PushDataOp(n);
68 | // OperationList[n + 2] = new CheckMultiSigOp();
69 | // int i = 1;
70 | // foreach (var item in pubKeyList)
71 | // {
72 | // OperationList[i++] = new PushDataOp(item.Item1.ToByteArray(item.Item2));
73 | // }
74 | //}
75 |
76 | //public void SetToP2SH_P2WPKH(PublicKey pubKey)
77 | //{
78 | // byte[] hash = hashFunc.ComputeHash(pubKey.ToByteArray(true)); // Always use compressed
79 | // OperationList = new IOperation[]
80 | // {
81 | // new PushDataOp(OP._0),
82 | // new PushDataOp(hash)
83 | // };
84 | //}
85 |
86 | public void SetToP2SH_P2WSH(Script witnessScript)
87 | {
88 | byte[] hash = witHashFunc.ComputeHash(witnessScript.ToByteArray());
89 | OperationList = new IOperation[]
90 | {
91 | new PushDataOp(OP._0),
92 | new PushDataOp(hash)
93 | };
94 | }
95 |
96 | //public void SetToCheckLocktimeVerify(PublicKey pubKey, bool compressed, LockTime lt)
97 | //{
98 | // OperationList = new IOperation[]
99 | // {
100 | // // TODO: change this to a better return type that doesn't have zeros
101 | // new PushDataOp(lt.ToByteArray(false).TrimEnd()),
102 | // new CheckLocktimeVerifyOp(),
103 | // new DROPOp(),
104 | // new PushDataOp(pubKey.ToByteArray(compressed)),
105 | // new CheckSigOp()
106 | // };
107 | //}
108 |
109 | public PubkeyScript ConvertP2WPKH_to_P2PKH()
110 | {
111 | if (GetRedeemScriptType() != RedeemScriptType.P2SH_P2WPKH)
112 | {
113 | throw new ArgumentException("This conversion only works for P2SH-P2WPKH redeem script types.");
114 | }
115 | IOperation pushHash = OperationList[1];
116 |
117 | PubkeyScript res = new PubkeyScript()
118 | {
119 | OperationList = new IOperation[]
120 | {
121 | new DUPOp(),
122 | new Hash160Op(),
123 | pushHash,
124 | new EqualVerifyOp(),
125 | new CheckSigOp()
126 | },
127 | };
128 |
129 | res.hashFunc = hashFunc;
130 | res.witHashFunc = witHashFunc;
131 |
132 | return res;
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/ScriptTypeEnums.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
7 | {
8 | ///
9 | /// Defined script types by
10 | /// , , ,
11 | /// classes
12 | ///
13 | public enum ScriptType
14 | {
15 | ///
16 | /// Unknown script type
17 | ///
18 | Unknown,
19 | ///
20 | /// Public key script used in
21 | ///
22 | ScriptPub,
23 | ///
24 | /// Signature script used in
25 | ///
26 | ScriptSig,
27 | ///
28 | /// Redeem script used in
29 | ///
30 | ScriptRedeem,
31 | ///
32 | /// Witness script used in
33 | ///
34 | ScriptWitness,
35 | }
36 |
37 |
38 | ///
39 | /// Defined script types in
40 | ///
41 | public enum PubkeyScriptType
42 | {
43 | ///
44 | /// An empty instance
45 | ///
46 | Empty,
47 | ///
48 | /// Unknown or undefined script type
49 | ///
50 | Unknown,
51 | ///
52 | /// "Pay to public key" public script
53 | ///
54 | P2PK,
55 | ///
56 | /// "Pay to public key hash" public script
57 | ///
58 | P2PKH,
59 | ///
60 | /// "Pay to script hash" public script
61 | ///
62 | P2SH,
63 | ///
64 | /// "Pay to multi-sig" public script
65 | ///
66 | P2MS,
67 | ///
68 | /// public script
69 | ///
70 | CheckLocktimeVerify,
71 | ///
72 | /// public script
73 | ///
74 | RETURN,
75 | ///
76 | /// "Pay to witness public key hash" public script
77 | ///
78 | P2WPKH,
79 | ///
80 | /// "Pay to witness script hash" public script
81 | ///
82 | P2WSH
83 | }
84 |
85 |
86 | ///
87 | /// Defined script types in
88 | ///
89 | public enum RedeemScriptType
90 | {
91 | ///
92 | /// An empty instance
93 | ///
94 | Empty,
95 | ///
96 | /// Unknown or undefined script type
97 | ///
98 | Unknown,
99 | ///
100 | /// Redeem script for m of n multi-signature scripts
101 | ///
102 | MultiSig,
103 | ///
104 | /// Redeem script for scripts
105 | ///
106 | CheckLocktimeVerify,
107 | ///
108 | /// Redeem script for "pay to witness pubkey hash in a pay to script hash" scripts
109 | ///
110 | P2SH_P2WPKH,
111 | ///
112 | /// Redeem script for "pay to witness script hash in a pay to script hash" scripts
113 | ///
114 | P2SH_P2WSH,
115 | ///
116 | /// Redeem script for "pay to witness script hash" scripts
117 | ///
118 | P2WSH,
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/Scripts/WitnessScript.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations;
7 |
8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts
9 | {
10 | ///
11 | /// Witness is not actually a script but items inside of the script.
12 | ///
13 | public class WitnessScript : Script, IWitnessScript
14 | {
15 | public WitnessScript()
16 | {
17 | IsWitness = true;
18 | OperationList = new IOperation[0];
19 | ScriptType = ScriptType.ScriptWitness;
20 | maxLenOrCount = 100; // TODO: set this to a real value and from ICoin
21 | }
22 |
23 |
24 |
25 | //public void SetToP2WPKH(Signature sig, PublicKey pubKey)
26 | //{
27 | // byte[] sigBa = sig.EncodeWithSigHashType();
28 | // byte[] pubkBa = pubKey.ToByteArray(true); // only compressed pubkeys are used in witness
29 |
30 | // OperationList = new IOperation[]
31 | // {
32 | // new PushDataOp(sigBa),
33 | // new PushDataOp(pubkBa)
34 | // };
35 | //}
36 |
37 | //public void SetToP2WSH_MultiSig(Signature[] sigs, RedeemScript redeem)
38 | //{
39 | // OperationList = new IOperation[sigs.Length + 2]; // OP_0 | Sig1 | sig2 | .... | sig(n) | redeemScript
40 |
41 | // OperationList[0] = new PushDataOp(OP._0);
42 |
43 | // for (int i = 1; i <= sigs.Length; i++)
44 | // {
45 | // OperationList[i] = new PushDataOp(sigs[i].EncodeWithSigHashType());
46 | // }
47 |
48 | // OperationList[OperationList.Length - 1] = new PushDataOp(new PushDataOp(redeem.ToByteArray()).ToByteArray(false));
49 | //}
50 |
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/TxIn.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts;
7 | using System;
8 |
9 | namespace BitcoinTransactionTool.Backend.Blockchain
10 | {
11 | public class TxIn : IDeserializable
12 | {
13 | ///
14 | /// Initializes a new instance of using parameters of the .
15 | ///
16 | public TxIn()
17 | {
18 | SetFields();
19 | Outpoint = new Outpoint();
20 | SigScript = new SignatureScript();
21 | }
22 |
23 | ///
24 | /// Initializes a new instance of using given parameters.
25 | ///
26 | ///
27 | /// Transaction output
28 | /// Signature script
29 | /// Sequence
30 | public TxIn(Outpoint op, SignatureScript sigScript, uint seq)
31 | {
32 | SetFields();
33 | if (op == null)
34 | throw new ArgumentNullException(nameof(op), "Outpoint can not be null!");
35 | if (sigScript == null)
36 | throw new ArgumentNullException(nameof(sigScript), "Signature script can not be null!");
37 |
38 | Outpoint = op;
39 | SigScript = sigScript;
40 | Sequence = seq;
41 | }
42 |
43 |
44 |
45 | public Outpoint Outpoint { get; set; }
46 | public ISignatureScript SigScript { get; set; }
47 | // TODO: read this about sequence and probably create a new variable type for it:
48 | // https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
49 | public uint Sequence { get; set; }
50 |
51 | internal int MinSize;
52 | internal int MaxSize;
53 |
54 |
55 |
56 | private void SetFields()
57 | {
58 | CompactInt temp = new CompactInt(10000 /*coin.ScriptSigMaxLength*/);
59 | int opSize = new Outpoint().Size;
60 | MinSize = opSize + 1 + 0 + sizeof(uint);
61 | MaxSize = opSize + temp.ToByteArray().Length + 10000 + sizeof(uint);
62 | }
63 |
64 |
65 | ///
66 | /// Converts this instance into its byte array representation.
67 | ///
68 | ///
69 | /// An array of bytes
70 | public byte[] Serialize()
71 | {
72 | if (Outpoint == null)
73 | throw new ArgumentNullException(nameof(Outpoint), "Outpoint can not be null.");
74 | if (SigScript == null)
75 | throw new ArgumentNullException(nameof(SigScript), "Signature script can not be null!");
76 |
77 |
78 | return ByteArray.ConcatArrays(
79 | Outpoint.Serialize(),
80 | SigScript.Serialize(),
81 | Sequence.ToByteArray(false)
82 | );
83 | }
84 |
85 |
86 |
87 | ///
88 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success.
89 | ///
90 | /// Byte array containing an .
91 | /// The offset inside the to start from.
92 | /// Error message (null if sucessful, otherwise will contain information about the failure).
93 | /// True if deserialization was successful, false if otherwise.
94 | public bool TryDeserialize(byte[] data, ref int offset, out string error)
95 | {
96 | if (offset < 0)
97 | {
98 | error = "Offset can not be negative.";
99 | return false;
100 | }
101 | if (data == null || data.Length - offset < MinSize)
102 | {
103 | error = "Data length is not valid.";
104 | return false;
105 | }
106 | // TODO: Outpoint and SigScript could be null, perform a check?
107 |
108 | if (!Outpoint.TryDeserialize(data, ref offset, out error))
109 | {
110 | return false;
111 | }
112 |
113 | if (!SigScript.TryDeserialize(data, ref offset, out error))
114 | {
115 | return false;
116 | }
117 |
118 | Sequence = data.SubArray(offset, sizeof(uint)).ToUInt32(false);
119 | offset += sizeof(uint);
120 |
121 | error = null;
122 | return true;
123 | }
124 |
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Blockchain/TxOut.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts;
7 | using System;
8 |
9 | namespace BitcoinTransactionTool.Backend.Blockchain
10 | {
11 | public class TxOut : IDeserializable
12 | {
13 | ///
14 | /// Initializes a new instance of using given parameters of the .
15 | ///
16 | public TxOut()
17 | {
18 | PubScript = new PubkeyScript();
19 | maxAmount = 21_000_000_0000_0000;
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of using given parameters.
24 | ///
25 | ///
26 | ///
27 | /// Payment amount in coin's smallest unit (eg. Satoshi).
28 | /// Public key script
29 | public TxOut(ulong amount, PubkeyScript pkScript)
30 | {
31 | if (amount > 21_000_000_0000_0000)
32 | throw new ArgumentOutOfRangeException(nameof(amount), "Can not spend more than coin's maximum supply.");
33 | if (pkScript == null)
34 | throw new ArgumentNullException(nameof(pkScript), $"Pubkey script can not be null.");
35 |
36 | Amount = amount;
37 | PubScript = pkScript;
38 |
39 | maxAmount = 21_000_000_0000_0000;
40 | }
41 |
42 |
43 |
44 | ///
45 | /// Minimum size of a TxOut. Amount(8) + CompactInt(1) + Script(0)
46 | ///
47 | internal int MinSize = sizeof(ulong) + 1;
48 | private readonly ulong maxAmount;
49 |
50 | public ulong Amount { get; set; }
51 | public IPubkeyScript PubScript { get; set; }
52 |
53 |
54 | ///
55 | /// Converts this instance into its byte array representation.
56 | ///
57 | ///
58 | ///
59 | /// An array of bytes.
60 | public byte[] Serialize()
61 | {
62 | if (PubScript == null)
63 | throw new ArgumentNullException(nameof(PubScript), $"PubKey script can not be null.");
64 | if (Amount > maxAmount)
65 | throw new ArgumentOutOfRangeException(nameof(Amount), "Can not spend more than coin's maximum supply.");
66 |
67 |
68 | return ByteArray.ConcatArrays(
69 | Amount.ToByteArray(false),
70 | PubScript.Serialize()
71 | );
72 | }
73 |
74 |
75 | ///
76 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success.
77 | ///
78 | /// Byte array containing a .
79 | /// The offset inside the to start from.
80 | /// Error message (null if sucessful, otherwise will contain information about the failure).
81 | /// True if deserialization was successful, false if otherwise.
82 | public bool TryDeserialize(byte[] data, ref int offset, out string error)
83 | {
84 | if (offset < 0)
85 | {
86 | error = "Offset can not be negative.";
87 | return false;
88 | }
89 | if (data == null || data.Length - offset < MinSize)
90 | {
91 | error = "Data length is not valid.";
92 | return false;
93 | }
94 |
95 |
96 | Amount = data.SubArray(offset, 8).ToUInt64(false);
97 | offset += 8;
98 | if (Amount > maxAmount)
99 | {
100 | error = "Amout exceeds maximum coin's supply.";
101 | return false;
102 | }
103 |
104 | if (!PubScript.TryDeserialize(data, ref offset, out error))
105 | {
106 | return false;
107 | }
108 |
109 | error = null;
110 | return true;
111 | }
112 |
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Constants.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend
7 | {
8 | public struct Constants
9 | {
10 | public const decimal Satoshi = 0.00000001m;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Cryptography/Hashing/IHashFunction.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 |
8 | namespace BitcoinTransactionTool.Backend.Cryptography.Hashing
9 | {
10 | public interface IHashFunction : IDisposable
11 | {
12 | ///
13 | /// Indicates whether the hash function should be performed twice on message.
14 | /// For example Double SHA256 that bitcoin uses.
15 | ///
16 | bool IsDouble { get; set; }
17 |
18 | ///
19 | /// Size of the hash result in bytes.
20 | ///
21 | int HashByteSize { get; }
22 |
23 | ///
24 | /// Size of the blocks used in each round.
25 | ///
26 | int BlockByteSize { get; }
27 |
28 | ///
29 | /// Computes the hash value for the specified byte array.
30 | ///
31 | /// The byte array to compute hash for
32 | /// The computed hash
33 | byte[] ComputeHash(byte[] data);
34 |
35 | ///
36 | /// Computes the hash value for the specified region of the specified byte array.
37 | ///
38 | /// The byte array to compute hash for
39 | /// The offset into the byte array from which to begin using data.
40 | /// The number of bytes in the array to use as data.
41 | /// The computed hash
42 | byte[] ComputeHash(byte[] buffer, int offset, int count);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Cryptography/Hashing/Sha1.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 | using System.Security.Cryptography;
8 |
9 | namespace BitcoinTransactionTool.Backend.Cryptography.Hashing
10 | {
11 | ///
12 | /// This is a wrapper around .Net SHA1 implementation.
13 | ///
14 | public class Sha1 : IHashFunction
15 | {
16 | ///
17 | /// Initializes a new instance of the .
18 | ///
19 | /// Determines whether the hash should be performed twice.
20 | public Sha1(bool isDouble = false)
21 | {
22 | IsDouble = isDouble;
23 | }
24 |
25 |
26 |
27 | ///
28 | /// Indicates whether the hash function should be performed twice on message.
29 | /// For example Double SHA256 that bitcoin uses.
30 | ///
31 | public bool IsDouble { get; set; }
32 |
33 | ///
34 | /// Size of the hash result in bytes.
35 | ///
36 | public virtual int HashByteSize => 20;
37 |
38 | ///
39 | /// Size of the blocks used in each round.
40 | ///
41 | public virtual int BlockByteSize => 64;
42 |
43 |
44 | private SHA1 hash = SHA1.Create();
45 |
46 |
47 |
48 | ///
49 | /// Computes the hash value for the specified byte array.
50 | ///
51 | ///
52 | ///
53 | /// The byte array to compute hash for
54 | /// The computed hash
55 | public byte[] ComputeHash(byte[] data)
56 | {
57 | if (disposedValue)
58 | throw new ObjectDisposedException("Instance was disposed.");
59 | if (data == null)
60 | throw new ArgumentNullException(nameof(data), "Data can not be null.");
61 |
62 | return IsDouble ? hash.ComputeHash(hash.ComputeHash(data)) : hash.ComputeHash(data);
63 | }
64 |
65 |
66 | ///
67 | /// Computes the hash value for the specified region of the specified byte array.
68 | ///
69 | ///
70 | ///
71 | ///
72 | /// The byte array to compute hash for
73 | /// The offset into the byte array from which to begin using data.
74 | /// The number of bytes in the array to use as data.
75 | /// The computed hash
76 | public byte[] ComputeHash(byte[] buffer, int offset, int count)
77 | {
78 | return ComputeHash(buffer.SubArray(offset, count));
79 | }
80 |
81 |
82 |
83 | #region IDisposable Support
84 | private bool disposedValue = false; // To detect redundant calls
85 |
86 | protected virtual void Dispose(bool disposing)
87 | {
88 | if (!disposedValue)
89 | {
90 | if (disposing)
91 | {
92 | if (hash != null)
93 | hash.Dispose();
94 | hash = null;
95 | }
96 |
97 | disposedValue = true;
98 | }
99 | }
100 |
101 | ///
102 | /// Releases all resources used by the current instance of the class.
103 | ///
104 | public void Dispose()
105 | {
106 | Dispose(true);
107 | }
108 | #endregion
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/Encoders/Base43.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 |
8 | namespace BitcoinTransactionTool.Backend.Encoders
9 | {
10 | ///
11 | /// Base-43 is a special encoding based on encoding that Electrum uses to encode transactions
12 | /// before turning them into QR code.
13 | ///
14 | public class Base43 : Base58
15 | {
16 | ///
17 | /// Initializes a new instance of the using parameters of the given
18 | /// and using default Base-43 characters.
19 | ///
20 | public Base43() : base()
21 | {
22 | // https://github.com/spesmilo/electrum/blob/b39c51adf7ef9d56bd45b1c30a86d4d415ef7940/electrum/bitcoin.py#L428
23 | b58Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:";
24 |
25 | baseValue = 43;
26 | logBaseValue = 679;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/IDeserializable.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | namespace BitcoinTransactionTool.Backend
7 | {
8 | public interface IDeserializable
9 | {
10 | ///
11 | /// Converts this instance into its byte array representation.
12 | ///
13 | /// An array of bytes
14 | byte[] Serialize();
15 |
16 | ///
17 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success.
18 | ///
19 | /// Byte array to use.
20 | /// The offset inside the to start from
21 | /// Error message (null if sucessful, otherwise will contain information about the failure)
22 | /// True if deserialization was successful, false if otherwise
23 | bool TryDeserialize(byte[] data, ref int offset, out string error);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/JsonConverterHelper.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts;
7 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations;
8 | using BitcoinTransactionTool.Backend.Encoders;
9 | using Newtonsoft.Json;
10 | using System;
11 | using System.Linq;
12 | using System.Text;
13 |
14 | namespace BitcoinTransactionTool.Backend
15 | {
16 | internal class ByteArrayHexConverter : JsonConverter
17 | {
18 | public ByteArrayHexConverter(bool reverseHex)
19 | {
20 | reverse = reverseHex;
21 | }
22 |
23 | private readonly bool reverse;
24 |
25 |
26 | public override bool CanRead => true;
27 | public override bool CanWrite => true;
28 |
29 | public override bool CanConvert(Type objectType) => objectType == typeof(byte[]);
30 |
31 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
32 | {
33 | if (reader.TokenType == JsonToken.String)
34 | {
35 | string hex = serializer.Deserialize(reader);
36 | return Base16.ToByteArray(hex);
37 | }
38 | return serializer.Deserialize(reader);
39 | }
40 |
41 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
42 | {
43 | byte[] data = (byte[])value;
44 | string hexString = (data == null) ? string.Empty : reverse ? data.Reverse().ToArray().ToBase16() : data.ToBase16();
45 | writer.WriteValue(hexString);
46 | }
47 | }
48 |
49 |
50 |
51 | internal class TransactionLocktimeConverter : JsonConverter
52 | {
53 | public override bool CanConvert(Type objectType)
54 | {
55 | return objectType == typeof(LockTime);
56 | }
57 |
58 | public override bool CanRead => false;
59 | public override bool CanWrite => true;
60 |
61 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
62 | {
63 | throw new NotImplementedException();
64 | }
65 |
66 |
67 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
68 | {
69 | writer.WriteValue(((LockTime)value).ToString());
70 | }
71 | }
72 |
73 |
74 | internal class TransactionScriptConverter : JsonConverter
75 | {
76 | public override bool CanConvert(Type objectType)
77 | {
78 | return objectType == typeof(SignatureScript)
79 | || objectType == typeof(PubkeyScript)
80 | || objectType == typeof(WitnessScript)
81 | || objectType == typeof(RedeemScript);
82 | }
83 |
84 | public override bool CanRead => false;
85 | public override bool CanWrite => true;
86 |
87 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
88 | {
89 | throw new NotImplementedException();
90 | }
91 |
92 |
93 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
94 | {
95 | IScript scr = (IScript)value;
96 |
97 | writer.WriteValue(ScriptToString(scr.OperationList));
98 | }
99 |
100 | private string ScriptToString(IOperation[] ops)
101 | {
102 | StringBuilder sb = new StringBuilder(ops.Length);
103 | foreach (var op in ops)
104 | {
105 | if (op is PushDataOp)
106 | {
107 | if (((PushDataOp)op).data == null)
108 | {
109 | string opName = op.OpValue.ToString();
110 | if (opName.Contains('_'))
111 | {
112 | sb.Append($"OP{opName} ");
113 | }
114 | else
115 | {
116 | sb.Append($"OP_{opName} ");
117 | }
118 | }
119 | else
120 | {
121 | sb.Append($"PushData<{((PushDataOp)op).data.ToBase16()}> ");
122 | }
123 | }
124 | else if (op is ReturnOp)
125 | {
126 | sb.Append($"OP_{op.OpValue.ToString()}<{((ReturnOp)op).Data.ToBase16()}>");
127 | }
128 | else if (op is IfElseOp)
129 | {
130 | string main = ScriptToString(((IfElseOp)op).mainOps);
131 | sb.Append($"OP_{op.OpValue.ToString()} {main} ");
132 | if (((IfElseOp)op).elseOps != null)
133 | {
134 | string branch = ScriptToString(((IfElseOp)op).elseOps);
135 | sb.Append($"OP_{OP.ELSE} {branch} ");
136 | }
137 | sb.Append($"OP_{OP.EndIf.ToString()} ");
138 | }
139 | else
140 | {
141 | sb.Append($"OP_{op.OpValue.ToString()} ");
142 | }
143 | }
144 |
145 | return sb.ToString().TrimEnd(' ');
146 | }
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/BitcoinTransactionTool/Backend/MVVM/BindableCommand.cs:
--------------------------------------------------------------------------------
1 | // Bitcoin Transaction Tool
2 | // Copyright (c) 2017 Coding Enthusiast
3 | // Distributed under the MIT software license, see the accompanying
4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5 |
6 | using System;
7 | using System.Windows.Input;
8 |
9 | namespace BitcoinTransactionTool.Backend.MVVM
10 | {
11 | public class BindableCommand : ICommand
12 | {
13 | public BindableCommand(Action