Skip to content

Commit af3208b

Browse files
committed
Resolve issue 3166.
These changes decode valid SIGHASH types on signatures in assembly (asm) representations of scriptSig scripts. This squashed commit incorporates substantial helpful feedback from jtimon, laanwj, and sipa.
1 parent 675d2fe commit af3208b

File tree

12 files changed

+206
-49
lines changed

12 files changed

+206
-49
lines changed

doc/release-notes.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,33 @@ git merge commit are mentioned.
3737

3838
### RPC and REST
3939

40+
Asm representations of scriptSig signatures now contain SIGHASH type decodes
41+
----------------------------------------------------------------------------
42+
43+
The `asm` property of each scriptSig now contains the decoded signature hash
44+
type for each signature that provides a valid defined hash type.
45+
46+
The following items contain assembly representations of scriptSig signatures
47+
and are affected by this change:
48+
49+
- RPC `getrawtransaction`
50+
- RPC `decoderawtransaction`
51+
- REST `/rest/tx/` (JSON format)
52+
- REST `/rest/block/` (JSON format when including extended tx details)
53+
- `bitcoin-tx -json`
54+
55+
For example, the `scriptSig.asm` property of a transaction input that
56+
previously showed an assembly representation of:
57+
58+
304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001
59+
60+
now shows as:
61+
62+
304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL]
63+
64+
Note that the output of the RPC `decodescript` did not change because it is
65+
configured specifically to process scriptPubKey and not scriptSig scripts.
66+
4067
### Configuration and command-line options
4168

4269
### Block and transaction handling

qa/rpc-tests/decodescript.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
from test_framework.test_framework import BitcoinTestFramework
77
from test_framework.util import *
8+
from test_framework.mininode import *
9+
from binascii import hexlify, unhexlify
10+
from cStringIO import StringIO
811

912
class DecodeScriptTest(BitcoinTestFramework):
1013
"""Tests decoding scripts via RPC command "decodescript"."""
@@ -107,10 +110,77 @@ def decodescript_script_pub_key(self):
107110
rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac')
108111
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
109112

113+
def decoderawtransaction_asm_sighashtype(self):
114+
"""Tests decoding scripts via RPC command "decoderawtransaction".
115+
116+
This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
117+
"""
118+
119+
# this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
120+
tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
121+
rpc_result = self.nodes[0].decoderawtransaction(tx)
122+
assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])
123+
124+
# this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
125+
# it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc
126+
# verify that we have not altered scriptPubKey decoding.
127+
tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
128+
rpc_result = self.nodes[0].decoderawtransaction(tx)
129+
assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])
130+
assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])
131+
assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
132+
assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
133+
txSave = CTransaction()
134+
txSave.deserialize(StringIO(unhexlify(tx)))
135+
136+
# make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
137+
tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
138+
rpc_result = self.nodes[0].decoderawtransaction(tx)
139+
assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])
140+
141+
# verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
142+
tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
143+
rpc_result = self.nodes[0].decoderawtransaction(tx)
144+
assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
145+
assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
146+
147+
# some more full transaction tests of varying specific scriptSigs. used instead of
148+
# tests in decodescript_script_sig because the decodescript RPC is specifically
149+
# for working on scriptPubKeys (argh!).
150+
push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)]
151+
signature = push_signature[2:]
152+
der_signature = signature[:-2]
153+
signature_sighash_decoded = der_signature + '[ALL]'
154+
signature_2 = der_signature + '82'
155+
push_signature_2 = '48' + signature_2
156+
signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'
157+
158+
# 1) P2PK scriptSig
159+
txSave.vin[0].scriptSig = unhexlify(push_signature)
160+
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
161+
assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
162+
163+
# make sure that the sighash decodes come out correctly for a more complex / lesser used case.
164+
txSave.vin[0].scriptSig = unhexlify(push_signature_2)
165+
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
166+
assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
167+
168+
# 2) multisig scriptSig
169+
txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2)
170+
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
171+
assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
172+
173+
# 3) test a scriptSig that contains more than push operations.
174+
# in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
175+
txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101')
176+
rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
177+
print(hexlify('636174'))
178+
assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
179+
110180
def run_test(self):
111181
self.decodescript_script_sig()
112182
self.decodescript_script_pub_key()
183+
self.decoderawtransaction_asm_sighashtype()
113184

114185
if __name__ == '__main__':
115186
DecodeScriptTest().main()
116-

src/bitcoin-tx.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,8 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
387387
CCoinsModifier coins = view.ModifyCoins(txid);
388388
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
389389
string err("Previous output scriptPubKey mismatch:\n");
390-
err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
391-
scriptPubKey.ToString();
390+
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
391+
ScriptToAsmStr(scriptPubKey);
392392
throw runtime_error(err);
393393
}
394394
if ((unsigned int)nOut >= coins->vout.size())

src/core_io.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class UniValue;
1616

1717
// core_read.cpp
1818
extern CScript ParseScript(const std::string& s);
19+
extern std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false);
1920
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
2021
extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
2122
extern uint256 ParseHashUV(const UniValue& v, const std::string& strName);
@@ -25,8 +26,7 @@ extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::strin
2526
// core_write.cpp
2627
extern std::string FormatScript(const CScript& script);
2728
extern std::string EncodeHexTx(const CTransaction& tx);
28-
extern void ScriptPubKeyToUniv(const CScript& scriptPubKey,
29-
UniValue& out, bool fIncludeHex);
29+
extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
3030
extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
3131

3232
#endif // BITCOIN_CORE_IO_H

src/core_write.cpp

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "utilmoneystr.h"
1616
#include "utilstrencodings.h"
1717

18+
#include <boost/assign/list_of.hpp>
1819
#include <boost/foreach.hpp>
1920

2021
using namespace std;
@@ -54,6 +55,67 @@ string FormatScript(const CScript& script)
5455
return ret.substr(0, ret.size() - 1);
5556
}
5657

58+
const map<unsigned char, string> mapSigHashTypes =
59+
boost::assign::map_list_of
60+
(static_cast<unsigned char>(SIGHASH_ALL), string("ALL"))
61+
(static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY"))
62+
(static_cast<unsigned char>(SIGHASH_NONE), string("NONE"))
63+
(static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY"))
64+
(static_cast<unsigned char>(SIGHASH_SINGLE), string("SINGLE"))
65+
(static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY"))
66+
;
67+
68+
/**
69+
* Create the assembly string representation of a CScript object.
70+
* @param[in] script CScript object to convert into the asm string representation.
71+
* @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format
72+
* of a signature. Only pass true for scripts you believe could contain signatures. For example,
73+
* pass false, or omit the this argument (defaults to false), for scriptPubKeys.
74+
*/
75+
string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
76+
{
77+
string str;
78+
opcodetype opcode;
79+
vector<unsigned char> vch;
80+
CScript::const_iterator pc = script.begin();
81+
while (pc < script.end()) {
82+
if (!str.empty()) {
83+
str += " ";
84+
}
85+
if (!script.GetOp(pc, opcode, vch)) {
86+
str += "[error]";
87+
return str;
88+
}
89+
if (0 <= opcode && opcode <= OP_PUSHDATA4) {
90+
if (vch.size() <= static_cast<vector<unsigned char>::size_type>(4)) {
91+
str += strprintf("%d", CScriptNum(vch, false).getint());
92+
} else {
93+
// the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
94+
if (fAttemptSighashDecode && !script.IsUnspendable()) {
95+
string strSigHashDecode;
96+
// goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.
97+
// this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to
98+
// the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the
99+
// checks in CheckSignatureEncoding.
100+
if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) {
101+
const unsigned char chSigHashType = vch.back();
102+
if (mapSigHashTypes.count(chSigHashType)) {
103+
strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]";
104+
vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.
105+
}
106+
}
107+
str += HexStr(vch) + strSigHashDecode;
108+
} else {
109+
str += HexStr(vch);
110+
}
111+
}
112+
} else {
113+
str += GetOpName(opcode);
114+
}
115+
}
116+
return str;
117+
}
118+
57119
string EncodeHexTx(const CTransaction& tx)
58120
{
59121
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
@@ -68,7 +130,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
68130
vector<CTxDestination> addresses;
69131
int nRequired;
70132

71-
out.pushKV("asm", scriptPubKey.ToString());
133+
out.pushKV("asm", ScriptToAsmStr(scriptPubKey));
72134
if (fIncludeHex)
73135
out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
74136

@@ -101,7 +163,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
101163
in.pushKV("txid", txin.prevout.hash.GetHex());
102164
in.pushKV("vout", (int64_t)txin.prevout.n);
103165
UniValue o(UniValue::VOBJ);
104-
o.pushKV("asm", txin.scriptSig.ToString());
166+
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
105167
o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
106168
in.pushKV("scriptSig", o);
107169
}

src/primitives/transaction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ std::string CTxIn::ToString() const
3636
if (prevout.IsNull())
3737
str += strprintf(", coinbase %s", HexStr(scriptSig));
3838
else
39-
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
39+
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
4040
if (nSequence != std::numeric_limits<unsigned int>::max())
4141
str += strprintf(", nSequence=%u", nSequence);
4242
str += ")";
@@ -56,7 +56,7 @@ uint256 CTxOut::GetHash() const
5656

5757
std::string CTxOut::ToString() const
5858
{
59-
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
59+
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
6060
}
6161

6262
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}

src/rpcrawtransaction.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
4141
vector<CTxDestination> addresses;
4242
int nRequired;
4343

44-
out.push_back(Pair("asm", scriptPubKey.ToString()));
44+
out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey)));
4545
if (fIncludeHex)
4646
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
4747

@@ -73,7 +73,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
7373
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
7474
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
7575
UniValue o(UniValue::VOBJ);
76-
o.push_back(Pair("asm", txin.scriptSig.ToString()));
76+
o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
7777
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
7878
in.push_back(Pair("scriptSig", o));
7979
}
@@ -665,8 +665,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
665665
CCoinsModifier coins = view.ModifyCoins(txid);
666666
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
667667
string err("Previous output scriptPubKey mismatch:\n");
668-
err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
669-
scriptPubKey.ToString();
668+
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
669+
ScriptToAsmStr(scriptPubKey);
670670
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
671671
}
672672
if ((unsigned int)nOut >= coins->vout.size())

src/script/interpreter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
188188
return true;
189189
}
190190

191-
bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
191+
bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
192192
// Empty signature. Not strictly DER encoded, but allowed to provide a
193193
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
194194
if (vchSig.size() == 0) {

src/script/interpreter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ enum
8383
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
8484
};
8585

86+
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
87+
8688
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
8789

8890
class BaseSignatureChecker

0 commit comments

Comments
 (0)