mmgen-msg: add export command
- export signature data relevant for a third-party verifier to JSON
This commit is contained in:
parent
aecc03e2a2
commit
4821fc203c
6 changed files with 72 additions and 21 deletions
|
|
@ -1 +1 @@
|
|||
March 2022
|
||||
April 2022
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
13.1.dev23
|
||||
13.1.dev24
|
||||
|
|
|
|||
|
|
@ -65,6 +65,17 @@ class MsgOps:
|
|||
if getattr(m,'failed_sids',None):
|
||||
sys.exit(1)
|
||||
|
||||
class export(sign):
|
||||
|
||||
async def __init__(self,msgfile,addr=None):
|
||||
|
||||
from .fileutil import write_data_to_file
|
||||
|
||||
write_data_to_file(
|
||||
outfile = 'signatures.json',
|
||||
data = SignedOnlineMsg( infile=msgfile ).get_json_for_export( addr ),
|
||||
desc = 'signature data' )
|
||||
|
||||
opts_data = {
|
||||
'text': {
|
||||
'desc': 'Perform message signing operations for MMGen addresses',
|
||||
|
|
@ -72,6 +83,7 @@ opts_data = {
|
|||
'[opts] create MESSAGE_TEXT ADDRESS_SPEC [...]',
|
||||
'[opts] sign MESSAGE_FILE [WALLET_FILE ...]',
|
||||
'[opts] verify MESSAGE_FILE',
|
||||
'[opts] export MESSAGE_FILE',
|
||||
],
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
|
|
@ -88,6 +100,8 @@ create - create a raw MMGen message file with specified message text for
|
|||
SPECIFIER below)
|
||||
sign - perform signing operation on an unsigned MMGen message file
|
||||
verify - verify and display the contents of a signed MMGen message file
|
||||
export - dump signed MMGen message file to ‘signatures.json’, including only
|
||||
data relevant for a third-party verifier
|
||||
|
||||
|
||||
ADDRESS SPECIFIER
|
||||
|
|
@ -149,6 +163,9 @@ $ mmgen-msg verify <signed message file>
|
|||
|
||||
Verify and display a single signature in the signed message file:
|
||||
$ mmgen-msg verify <signed message file> DEADBEEF:B:98
|
||||
|
||||
Export data relevant for a third-party verifier to ‘signatures.json’:
|
||||
$ mmgen-msg export <signed message file>
|
||||
"""
|
||||
},
|
||||
'code': {
|
||||
|
|
@ -174,10 +191,10 @@ async def main():
|
|||
if len(cmd_args) < 1:
|
||||
opts.usage()
|
||||
await MsgOps.sign( cmd_args[0], cmd_args[1:] )
|
||||
elif op == 'verify':
|
||||
elif op in ('verify','export'):
|
||||
if len(cmd_args) not in (1,2):
|
||||
opts.usage()
|
||||
await MsgOps.verify( cmd_args[0], cmd_args[1] if len(cmd_args) == 2 else None )
|
||||
await getattr(MsgOps,op)( cmd_args[0], cmd_args[1] if len(cmd_args) == 2 else None )
|
||||
else:
|
||||
die(1,f'{op!r}: unrecognized operation')
|
||||
|
||||
|
|
|
|||
49
mmgen/msg.py
49
mmgen/msg.py
|
|
@ -258,7 +258,7 @@ class coin_msg:
|
|||
|
||||
class signed_online(signed):
|
||||
|
||||
async def verify(self,addr=None,summary=False):
|
||||
def get_sigs(self,addr):
|
||||
|
||||
if addr:
|
||||
mmaddr = MMGenID(self.proto,addr)
|
||||
|
|
@ -266,23 +266,40 @@ class coin_msg:
|
|||
else:
|
||||
sigs = self.sigs
|
||||
|
||||
if sigs:
|
||||
from .rpc import rpc_init
|
||||
self.rpc = await rpc_init(self.proto)
|
||||
|
||||
for k,v in sigs.items():
|
||||
ret = await self.do_verify(
|
||||
addr = v.get('addr_p2pkh') or v['addr'],
|
||||
sig = v['sig'],
|
||||
message = self.data['message'] )
|
||||
if not ret:
|
||||
die(3,f'Invalid signature for address {k} ({v["addr"]})')
|
||||
|
||||
if summary:
|
||||
msg('{} signature{} verified'.format( len(sigs), suf(sigs) ))
|
||||
else:
|
||||
if not sigs:
|
||||
die(1,'No signatures')
|
||||
|
||||
return sigs
|
||||
|
||||
async def verify(self,addr=None,summary=False):
|
||||
|
||||
sigs = self.get_sigs(addr)
|
||||
|
||||
from .rpc import rpc_init
|
||||
self.rpc = await rpc_init(self.proto)
|
||||
|
||||
for k,v in sigs.items():
|
||||
ret = await self.do_verify(
|
||||
addr = v.get('addr_p2pkh') or v['addr'],
|
||||
sig = v['sig'],
|
||||
message = self.data['message'] )
|
||||
if not ret:
|
||||
die(3,f'Invalid signature for address {k} ({v["addr"]})')
|
||||
|
||||
if summary:
|
||||
msg('{} signature{} verified'.format( len(sigs), suf(sigs) ))
|
||||
|
||||
def get_json_for_export(self,addr=None):
|
||||
return json.dumps(
|
||||
{
|
||||
'message': self.data['message'],
|
||||
'network': self.data['network'].upper(),
|
||||
'signatures': tuple( self.get_sigs(addr).values() ),
|
||||
},
|
||||
sort_keys = True,
|
||||
indent = 4
|
||||
)
|
||||
|
||||
def _get_obj(clsname,coin=None,network='mainnet',infile=None,data=None,*args,**kwargs):
|
||||
|
||||
assert not args, 'msg:_get_obj(): only keyword args allowed'
|
||||
|
|
|
|||
|
|
@ -266,6 +266,8 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
('bob_msgverify', 'verifying the message file (all addresses)'),
|
||||
('bob_msgverify_raw', 'verifying the raw message file (all addresses)'),
|
||||
('bob_msgverify_single', 'verifying the message file (single address)'),
|
||||
('bob_msgexport', 'exporting the message file'),
|
||||
('bob_msgexport_single', 'exporting the message file (single address)'),
|
||||
|
||||
('stop', 'stopping regtest daemon'),
|
||||
)
|
||||
|
|
@ -1083,12 +1085,12 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
fn2 = get_file_with_ext(self.tmpdir,'bip39')
|
||||
return self.bob_msgsign([fn2,fn1])
|
||||
|
||||
def bob_msgverify(self,addr=None,ext='sigmsg.json'):
|
||||
def bob_msgverify(self,addr=None,ext='sigmsg.json',cmd='verify'):
|
||||
return self.spawn(
|
||||
'mmgen-msg', [
|
||||
'--bob',
|
||||
f'--outdir={self.tmpdir}',
|
||||
'verify',
|
||||
cmd,
|
||||
get_file_with_ext(self.tmpdir,ext),
|
||||
] + ([addr] if addr else []) )
|
||||
|
||||
|
|
@ -1101,6 +1103,15 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
sid = self._user_sid('bob')
|
||||
return self.bob_msgverify(addr=f'{sid}:{self.dfl_mmtype}:1')
|
||||
|
||||
def bob_msgexport(self,addr=None):
|
||||
t = self.bob_msgverify( addr=addr, cmd='export' )
|
||||
t.written_to_file('data')
|
||||
return t
|
||||
|
||||
def bob_msgexport_single(self):
|
||||
sid = self._user_sid('bob')
|
||||
return self.bob_msgexport(addr=f'{sid}:{self.dfl_mmtype}:1')
|
||||
|
||||
def stop(self):
|
||||
if opt.no_daemon_stop:
|
||||
self.spawn('',msg_only=True)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,12 @@ async def run_test(network_id):
|
|||
pumsg('\nTesting single address verification:\n')
|
||||
await m.verify('A091ABAA:111',summary=opt.verbose)
|
||||
|
||||
pumsg('\nTesting JSON dump for export:\n')
|
||||
msg( m.get_json_for_export() )
|
||||
|
||||
pumsg('\nTesting single address JSON dump for export:\n')
|
||||
msg( m.get_json_for_export('A091ABAA:111') )
|
||||
|
||||
stop_test_daemons(network_id)
|
||||
|
||||
msg('\n')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue