mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-07-26 19:42:46 +02:00
Merge remote-tracking branch 'origin/feat-std-key-formats' into dev
This commit is contained in:
+5
-2
@@ -422,8 +422,11 @@ def _load_or_create_identity_key(path: Optional[str] = None) -> bytes:
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to load identity key: {e}")
|
||||
|
||||
# Generate new random key
|
||||
key = os.urandom(32)
|
||||
# Generate new key via MeshCore-compatible keygen; store 32-byte private scalar.
|
||||
from repeater.keygen import generate_meshcore_keypair
|
||||
|
||||
_, private_key = generate_meshcore_keypair()
|
||||
key = private_key[:32]
|
||||
|
||||
# Save it
|
||||
try:
|
||||
|
||||
+27
-14
@@ -14,6 +14,11 @@ from typing import Optional, Tuple
|
||||
from nacl.bindings import crypto_scalarmult_ed25519_base_noclamp
|
||||
|
||||
|
||||
def _has_disallowed_public_prefix(public_key: bytes) -> bool:
|
||||
"""Return True when public key starts with a forbidden prefix byte."""
|
||||
return bool(public_key) and public_key[0] in (0x00, 0xFF)
|
||||
|
||||
|
||||
def generate_meshcore_keypair() -> Tuple[bytes, bytes]:
|
||||
"""Generate a MeshCore-compatible Ed25519 keypair.
|
||||
|
||||
@@ -21,25 +26,30 @@ def generate_meshcore_keypair() -> Tuple[bytes, bytes]:
|
||||
(public_key, private_key) as raw bytes.
|
||||
public_key is 32 bytes, private_key is 64 bytes.
|
||||
"""
|
||||
# 1. Random 32-byte seed
|
||||
seed = secrets.token_bytes(32)
|
||||
while True:
|
||||
# 1. Random 32-byte seed
|
||||
seed = secrets.token_bytes(32)
|
||||
|
||||
# 2. SHA-512 hash
|
||||
digest = hashlib.sha512(seed).digest()
|
||||
# 2. SHA-512 hash
|
||||
digest = hashlib.sha512(seed).digest()
|
||||
|
||||
# 3. Ed25519 scalar clamping on first 32 bytes
|
||||
clamped = bytearray(digest[:32])
|
||||
clamped[0] &= 248 # Clear bottom 3 bits
|
||||
clamped[31] &= 63 # Clear top 2 bits
|
||||
clamped[31] |= 64 # Set bit 6
|
||||
# 3. Ed25519 scalar clamping on first 32 bytes
|
||||
clamped = bytearray(digest[:32])
|
||||
clamped[0] &= 248 # Clear bottom 3 bits
|
||||
clamped[31] &= 63 # Clear top 2 bits
|
||||
clamped[31] |= 64 # Set bit 6
|
||||
|
||||
# 4. Derive public key
|
||||
public_key = crypto_scalarmult_ed25519_base_noclamp(bytes(clamped))
|
||||
# 4. Derive public key
|
||||
public_key = crypto_scalarmult_ed25519_base_noclamp(bytes(clamped))
|
||||
|
||||
# 5. Private key = [clamped_scalar][sha512_upper_half]
|
||||
private_key = bytes(clamped) + digest[32:64]
|
||||
# Disallow keys with 0x00 / 0xFF leading byte.
|
||||
if _has_disallowed_public_prefix(public_key):
|
||||
continue
|
||||
|
||||
return public_key, private_key
|
||||
# 5. Private key = [clamped_scalar][sha512_upper_half]
|
||||
private_key = bytes(clamped) + digest[32:64]
|
||||
|
||||
return public_key, private_key
|
||||
|
||||
|
||||
def generate_vanity_key(
|
||||
@@ -57,6 +67,9 @@ def generate_vanity_key(
|
||||
"""
|
||||
target = prefix.upper()
|
||||
|
||||
if target.startswith("00") or target.startswith("FF"):
|
||||
return None
|
||||
|
||||
for attempt in range(1, max_iterations + 1):
|
||||
pub, priv = generate_meshcore_keypair()
|
||||
if pub.hex().upper().startswith(target):
|
||||
|
||||
@@ -4256,9 +4256,11 @@ class APIEndpoints:
|
||||
key_was_generated = False
|
||||
if not identity_key:
|
||||
try:
|
||||
# Generate a new random 32-byte key (same method as config.py)
|
||||
random_key = os.urandom(32)
|
||||
identity_key = random_key.hex()
|
||||
# Use MeshCore-compatible keygen and store 32-byte private scalar hex.
|
||||
from repeater.keygen import generate_meshcore_keypair
|
||||
|
||||
_, private_key = generate_meshcore_keypair()
|
||||
identity_key = private_key[:32].hex()
|
||||
key_was_generated = True
|
||||
logger.info(f"Auto-generated identity key for '{name}': {identity_key[:16]}...")
|
||||
except Exception as gen_error:
|
||||
|
||||
Reference in New Issue
Block a user