feat: add node startup flow
This commit is contained in:
64
packages/node/meshnet_node/wallet.py
Normal file
64
packages/node/meshnet_node/wallet.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""Solana wallet management — load or generate an Ed25519 keypair.
|
||||
|
||||
Solana keypair format: 64-byte array stored as JSON list of ints.
|
||||
bytes 0-31: private scalar (seed)
|
||||
bytes 32-63: public key (on-curve point)
|
||||
Wallet address: base58-encoded 32-byte public key.
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
_DEFAULT_WALLET_PATH = Path.home() / ".config" / "meshnet" / "wallet.json"
|
||||
|
||||
_B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
|
||||
|
||||
def _b58encode(data: bytes) -> str:
|
||||
n = int.from_bytes(data, "big")
|
||||
chars: list[str] = []
|
||||
while n:
|
||||
n, rem = divmod(n, 58)
|
||||
chars.append(_B58_ALPHABET[rem])
|
||||
leading = 0
|
||||
for b in data:
|
||||
if b == 0:
|
||||
leading += 1
|
||||
else:
|
||||
break
|
||||
return "1" * leading + "".join(reversed(chars))
|
||||
|
||||
|
||||
def load_or_create_wallet(
|
||||
path: Path = _DEFAULT_WALLET_PATH,
|
||||
) -> tuple[bytes, bytes, str]:
|
||||
"""Return (secret_32, public_32, address_base58).
|
||||
|
||||
Loads from *path* if it exists; otherwise generates a new keypair and
|
||||
saves it. The parent directory is created if needed.
|
||||
"""
|
||||
if path.exists():
|
||||
mode = path.stat().st_mode & 0o777
|
||||
if mode & 0o077:
|
||||
path.chmod(0o600)
|
||||
raw = bytes(json.loads(path.read_text()))
|
||||
if len(raw) != 64:
|
||||
raise ValueError(f"Wallet at {path} has unexpected length {len(raw)}, expected 64")
|
||||
secret, public = raw[:32], raw[32:]
|
||||
return secret, public, _b58encode(public)
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
||||
from cryptography.hazmat.primitives.serialization import (
|
||||
Encoding, NoEncryption, PrivateFormat, PublicFormat,
|
||||
)
|
||||
|
||||
priv = Ed25519PrivateKey.generate()
|
||||
secret = priv.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
|
||||
public = priv.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
|
||||
keypair = list(secret) + list(public)
|
||||
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(keypair))
|
||||
path.chmod(0o600)
|
||||
|
||||
return secret, public, _b58encode(public)
|
||||
Reference in New Issue
Block a user