lunalib 1.2.3__py3-none-any.whl → 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core/wallet.py +407 -346
- lunalib/core/blockchain.py +315 -150
- lunalib/core/crypto.py +265 -27
- lunalib/core/mempool.py +104 -102
- lunalib/core/sm2.py +723 -0
- lunalib/core/wallet.py +850 -319
- lunalib/transactions/security.py +87 -25
- lunalib/transactions/transactions.py +247 -431
- {lunalib-1.2.3.dist-info → lunalib-1.5.0.dist-info}/METADATA +1 -1
- {lunalib-1.2.3.dist-info → lunalib-1.5.0.dist-info}/RECORD +14 -13
- transactions/transactions.py +423 -378
- {lunalib-1.2.3.dist-info → lunalib-1.5.0.dist-info}/WHEEL +0 -0
- {lunalib-1.2.3.dist-info → lunalib-1.5.0.dist-info}/entry_points.txt +0 -0
- {lunalib-1.2.3.dist-info → lunalib-1.5.0.dist-info}/top_level.txt +0 -0
lunalib/transactions/security.py
CHANGED
|
@@ -3,7 +3,7 @@ import hashlib
|
|
|
3
3
|
from typing import Dict, Tuple
|
|
4
4
|
|
|
5
5
|
class TransactionSecurity:
|
|
6
|
-
"""Enhanced transaction security system"""
|
|
6
|
+
"""Enhanced transaction security system with SM2 support"""
|
|
7
7
|
|
|
8
8
|
def __init__(self):
|
|
9
9
|
self.min_transaction_amount = 0.000001
|
|
@@ -11,9 +11,20 @@ class TransactionSecurity:
|
|
|
11
11
|
self.required_fee = 0.00001
|
|
12
12
|
self.rate_limits = {}
|
|
13
13
|
self.blacklisted_addresses = set()
|
|
14
|
+
|
|
15
|
+
# Try to import SM2 KeyManager
|
|
16
|
+
try:
|
|
17
|
+
from ..core.crypto import KeyManager as SM2KeyManager
|
|
18
|
+
self.key_manager = SM2KeyManager()
|
|
19
|
+
self.sm2_available = True
|
|
20
|
+
print("[SECURITY] SM2 KeyManager loaded successfully")
|
|
21
|
+
except ImportError as e:
|
|
22
|
+
self.key_manager = None
|
|
23
|
+
self.sm2_available = False
|
|
24
|
+
print(f"[SECURITY] SM2 KeyManager not available: {e}")
|
|
14
25
|
|
|
15
26
|
def validate_transaction_security(self, transaction: Dict) -> Tuple[bool, str]:
|
|
16
|
-
"""Comprehensive transaction security validation"""
|
|
27
|
+
"""Comprehensive transaction security validation with SM2"""
|
|
17
28
|
tx_type = transaction.get("type", "").lower()
|
|
18
29
|
|
|
19
30
|
if tx_type == "gtx_genesis":
|
|
@@ -58,7 +69,7 @@ class TransactionSecurity:
|
|
|
58
69
|
return True, "Valid reward transaction"
|
|
59
70
|
|
|
60
71
|
def _validate_transfer_transaction(self, transaction: Dict) -> Tuple[bool, str]:
|
|
61
|
-
"""Validate transfer transaction"""
|
|
72
|
+
"""Validate transfer transaction with SM2 signature"""
|
|
62
73
|
required_fields = ["from", "to", "amount", "signature", "public_key", "nonce"]
|
|
63
74
|
for field in required_fields:
|
|
64
75
|
if field not in transaction:
|
|
@@ -76,9 +87,9 @@ class TransactionSecurity:
|
|
|
76
87
|
if fee < self.required_fee:
|
|
77
88
|
return False, f"Insufficient fee: {fee} (required: {self.required_fee})"
|
|
78
89
|
|
|
79
|
-
# Signature validation
|
|
80
|
-
if not self.
|
|
81
|
-
return False, "Invalid signature"
|
|
90
|
+
# SM2 Signature validation
|
|
91
|
+
if not self._validate_signature_sm2(transaction):
|
|
92
|
+
return False, "Invalid SM2 signature"
|
|
82
93
|
|
|
83
94
|
# Anti-spam checks
|
|
84
95
|
from_address = transaction.get("from", "")
|
|
@@ -90,6 +101,65 @@ class TransactionSecurity:
|
|
|
90
101
|
|
|
91
102
|
return True, "Valid transfer transaction"
|
|
92
103
|
|
|
104
|
+
def _validate_signature_sm2(self, transaction: Dict) -> bool:
|
|
105
|
+
"""Validate transaction signature using SM2"""
|
|
106
|
+
try:
|
|
107
|
+
signature = transaction.get("signature", "")
|
|
108
|
+
public_key = transaction.get("public_key", "")
|
|
109
|
+
tx_type = transaction.get("type", "").lower()
|
|
110
|
+
|
|
111
|
+
# Skip system transactions
|
|
112
|
+
if tx_type in ["gtx_genesis", "reward"]:
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
# For unsigned test transactions
|
|
116
|
+
if signature in ["system", "unsigned", "test"]:
|
|
117
|
+
print(f"[SECURITY] Skipping signature check for system/unsigned transaction")
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
# Check SM2 signature length (should be 128 hex chars = 64 bytes)
|
|
121
|
+
if len(signature) != 128:
|
|
122
|
+
print(f"[SECURITY] Invalid SM2 signature length: {len(signature)} (expected 128)")
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
# Check if all characters are valid hex
|
|
126
|
+
if not all(c in "0123456789abcdefABCDEF" for c in signature):
|
|
127
|
+
print(f"[SECURITY] Signature contains non-hex characters")
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
# Check public key format (should start with '04' for uncompressed)
|
|
131
|
+
if not public_key.startswith('04'):
|
|
132
|
+
print(f"[SECURITY] Invalid public key format: {public_key[:20]}...")
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
# Use KeyManager for verification if available
|
|
136
|
+
if self.sm2_available and self.key_manager:
|
|
137
|
+
# Create signing data string
|
|
138
|
+
signing_data = self._get_signing_data(transaction)
|
|
139
|
+
|
|
140
|
+
# Verify signature
|
|
141
|
+
is_valid = self.key_manager.verify_signature(signing_data, signature, public_key)
|
|
142
|
+
print(f"[SECURITY] SM2 signature verification: {is_valid}")
|
|
143
|
+
return is_valid
|
|
144
|
+
|
|
145
|
+
# Fallback: Basic format check if SM2 not available
|
|
146
|
+
print(f"[SECURITY] SM2 not available, using basic signature validation")
|
|
147
|
+
return len(signature) == 128 and signature.startswith(('04', '03', '02'))
|
|
148
|
+
|
|
149
|
+
except Exception as e:
|
|
150
|
+
print(f"[SECURITY] Signature validation error: {e}")
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
def _get_signing_data(self, transaction: Dict) -> str:
|
|
154
|
+
"""Create data string for signing"""
|
|
155
|
+
# Create copy without signature and hash
|
|
156
|
+
tx_copy = {k: v for k, v in transaction.items()
|
|
157
|
+
if k not in ['signature', 'hash']}
|
|
158
|
+
|
|
159
|
+
# Sort keys and convert to string
|
|
160
|
+
import json
|
|
161
|
+
return json.dumps(tx_copy, sort_keys=True)
|
|
162
|
+
|
|
93
163
|
def _validate_mining_proof(self, transaction: Dict) -> bool:
|
|
94
164
|
"""Validate mining proof-of-work"""
|
|
95
165
|
try:
|
|
@@ -103,20 +173,9 @@ class TransactionSecurity:
|
|
|
103
173
|
return False
|
|
104
174
|
|
|
105
175
|
def _validate_signature(self, transaction: Dict) -> bool:
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
public_key = transaction.get("public_key", "")
|
|
110
|
-
|
|
111
|
-
# Basic format validation
|
|
112
|
-
if len(signature) != 64:
|
|
113
|
-
return False
|
|
114
|
-
|
|
115
|
-
# In production, use proper ECDSA verification
|
|
116
|
-
# For now, simplified check
|
|
117
|
-
return all(c in "0123456789abcdef" for c in signature.lower())
|
|
118
|
-
except:
|
|
119
|
-
return False
|
|
176
|
+
"""Legacy signature validation (for backward compatibility)"""
|
|
177
|
+
print(f"[SECURITY] Using legacy signature validation")
|
|
178
|
+
return self._validate_signature_sm2(transaction)
|
|
120
179
|
|
|
121
180
|
def _check_rate_limit(self, address: str) -> bool:
|
|
122
181
|
"""Check transaction rate limiting"""
|
|
@@ -144,17 +203,20 @@ class TransactionSecurity:
|
|
|
144
203
|
self.blacklisted_addresses.add(address.lower())
|
|
145
204
|
|
|
146
205
|
def calculate_security_score(self, transaction: Dict) -> int:
|
|
147
|
-
"""Calculate security score for transaction"""
|
|
206
|
+
"""Calculate security score for transaction with SM2 bonus"""
|
|
148
207
|
score = 0
|
|
149
208
|
|
|
150
|
-
# Signature strength
|
|
209
|
+
# Signature strength (SM2 gives higher score)
|
|
151
210
|
signature = transaction.get("signature", "")
|
|
152
|
-
if len(signature) ==
|
|
211
|
+
if len(signature) == 128: # SM2 signature
|
|
212
|
+
score += 60 # Higher score for SM2
|
|
213
|
+
elif len(signature) == 64: # Legacy ECDSA
|
|
153
214
|
score += 40
|
|
154
215
|
|
|
155
216
|
# Public key presence
|
|
156
|
-
|
|
157
|
-
|
|
217
|
+
public_key = transaction.get("public_key", "")
|
|
218
|
+
if public_key and public_key.startswith('04'):
|
|
219
|
+
score += 30 # SM2 uncompressed format
|
|
158
220
|
|
|
159
221
|
# Timestamp freshness
|
|
160
222
|
timestamp = transaction.get("timestamp", 0)
|