new module: proto.xmr.subaddress
Given a master address, account idx and address idx, generate a subaddress.
This commit is contained in:
parent
b47fff4a9f
commit
ef61dd104c
3 changed files with 94 additions and 1 deletions
|
|
@ -1 +1 @@
|
|||
16.3.0dev24
|
||||
16.3.0dev25
|
||||
|
|
|
|||
50
mmgen/proto/xmr/subaddress.py
Normal file
50
mmgen/proto/xmr/subaddress.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# ~/.local/lib/python3.13/site-packages/monero/wallet.py
|
||||
|
||||
from nacl import bindings as nacl
|
||||
|
||||
from ...util2 import get_keccak
|
||||
from ...addr import MoneroIdx
|
||||
|
||||
from .addrgen import b58enc
|
||||
|
||||
keccak_256 = get_keccak()
|
||||
|
||||
add = nacl.crypto_core_ed25519_add
|
||||
scalarmult_base = nacl.crypto_scalarmult_ed25519_base_noclamp
|
||||
scalarmult = nacl.crypto_scalarmult_ed25519_noclamp
|
||||
|
||||
# src/ringct/rctTypes.h:
|
||||
H = bytes.fromhex('8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94')
|
||||
|
||||
def scalar_reduce(v):
|
||||
return nacl.crypto_core_ed25519_scalar_reduce(v.ljust(64, b'\0'))
|
||||
|
||||
def get_subaddress(*, proto, master_addr, master_svk, acct_idx, addr_idx):
|
||||
"""
|
||||
Generate subaddress for given account index and address index
|
||||
"""
|
||||
|
||||
if acct_idx == addr_idx == 0:
|
||||
return master_addr
|
||||
|
||||
acct_idx = MoneroIdx(acct_idx)
|
||||
addr_idx = MoneroIdx(addr_idx)
|
||||
|
||||
master_psk = proto.decode_addr(master_addr).bytes[:32] # => psk + pvk
|
||||
|
||||
hash_in = (
|
||||
b'SubAddr\0'
|
||||
+ master_svk
|
||||
+ acct_idx.to_bytes(4, 'little')
|
||||
+ addr_idx.to_bytes(4, 'little'))
|
||||
|
||||
m = keccak_256(hash_in).digest()
|
||||
|
||||
# psk = master_psk + m * B
|
||||
psk = add(master_psk, scalarmult_base(scalar_reduce(m)))
|
||||
|
||||
# pvk = master_svk * psk
|
||||
pvk = scalarmult(master_svk, psk)
|
||||
|
||||
data = proto.addr_fmt_to_ver_bytes['monero_sub'] + psk + pvk
|
||||
return b58enc(data + keccak_256(data).digest()[:4])
|
||||
|
|
@ -60,6 +60,49 @@ class unit_tests:
|
|||
|
||||
return True
|
||||
|
||||
def xmr_subaddress(self, name, ut, desc='generating XMR subaddresses'):
|
||||
vectors = [
|
||||
['45mLzbVEU5jNEN5qrfvbWMEbBK3LHDdzvgtSxiBgoUs7WYyKatHdzzEM612XpKv3xR52JZq5V7GURSbp5EqpqvQ7UCPrmwU'],
|
||||
['82x63Tnxi8xTLkU1WvYm3MTDcFZek6AyN1W6TppMtTnUVuK11GRGtXGJLQKCB5cGU7hukQuoKQsMm1hvnW3mrGxY8JQqVWD'],
|
||||
[
|
||||
'8AEK8kKkU5ddKr8PL32RgoUW97fDeMFrJNJ3Fh15RWfFUqjodYcd6oAjCdrLrYT3io22vFUkB3FAP7r1hgY39bzEKtHGChq',
|
||||
'86JzhV6CUy1bFrLoLJ23Qmgmphz5bsMVubLosp87RRstNxCsderXWvRhEe3s1PWdjv1j6mG9t4hSSQ1JXu1bAZRDSvadW9m',
|
||||
'88jM6aonkzqP3EcHYCQnMSAHrvv3ZBZo8gC1sVEc4nUgBZsPww3WEx6jfsdLxbWBLE3zVDvp1w6CWAPeybrSF1Cx3BH3EYC',
|
||||
]
|
||||
]
|
||||
from mmgen.proto.xmr.subaddress import get_subaddress
|
||||
from mmgen.addrlist import KeyAddrList
|
||||
from mmgen.cfg import Config
|
||||
from mmgen.protocol import init_proto
|
||||
from mmgen.seed import Seed
|
||||
with open('test/ref/FE3C6545.hex') as fh:
|
||||
seed_hex = fh.read().strip()
|
||||
cfg = Config()
|
||||
proto = init_proto(cfg, 'xmr', network='regtest')
|
||||
kal = KeyAddrList(
|
||||
cfg = cfg,
|
||||
proto = proto,
|
||||
seed = Seed(cfg, seed_bin=bytes.fromhex(seed_hex)),
|
||||
addr_idxs = '4',
|
||||
mmtype = 'M',
|
||||
skip_chksum = True)
|
||||
data = kal.data[0]
|
||||
for acct_idx, addr_idx in (
|
||||
(0, 0),
|
||||
(1, 0),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
(2, 2)):
|
||||
addr = get_subaddress(
|
||||
proto = proto,
|
||||
master_addr = data.addr,
|
||||
master_svk = bytes.fromhex(data.viewkey),
|
||||
acct_idx = acct_idx,
|
||||
addr_idx = addr_idx)
|
||||
vmsg(f'{acct_idx=} {addr_idx=} {addr=}')
|
||||
assert addr == vectors[acct_idx][addr_idx]
|
||||
return True
|
||||
|
||||
def xmrwallet_uarg_info(self, name, ut, desc='dict xmrwallet.xmrwallet_uarg_info'): # WIP
|
||||
from mmgen.xmrwallet import uarg_info
|
||||
vs = namedtuple('vector_data', ['text', 'groups'])
|
||||
|
|
|
|||
Loading…
Reference in a new issue