1
1
import json
2
2
from pathlib import Path
3
- from typing import Dict , Optional , Union
3
+ from typing import Dict , List , Optional , Union
4
4
5
5
import base58
6
6
from nacl .exceptions import BadSignatureError as NaclBadSignatureError
@@ -22,7 +22,7 @@ class SOLAccount(BaseAccount):
22
22
_private_key : PrivateKey
23
23
24
24
def __init__ (self , private_key : bytes ):
25
- self .private_key = private_key
25
+ self .private_key = parse_private_key ( private_key_from_bytes ( private_key ))
26
26
self ._signing_key = SigningKey (self .private_key )
27
27
self ._private_key = self ._signing_key .to_curve25519_private_key ()
28
28
@@ -79,7 +79,7 @@ def verify_signature(
79
79
public_key: The public key to use for verification. Can be a base58 encoded string or bytes.
80
80
message: The message to verify. Can be an utf-8 string or bytes.
81
81
Raises:
82
- BadSignatureError: If the signature is invalid.
82
+ BadSignatureError: If the signature is invalid.!
83
83
"""
84
84
if isinstance (signature , str ):
85
85
signature = base58 .b58decode (signature )
@@ -91,3 +91,91 @@ def verify_signature(
91
91
VerifyKey (public_key ).verify (message , signature )
92
92
except NaclBadSignatureError as e :
93
93
raise BadSignatureError from e
94
+
95
+
96
+ def private_key_from_bytes (
97
+ private_key_bytes : bytes , output_format : str = "base58"
98
+ ) -> Union [str , List [int ], bytes ]:
99
+ """
100
+ Convert a Solana private key in bytes back to different formats (base58 string, uint8 list, or raw bytes).
101
+
102
+ - For base58 string: Encode the bytes into a base58 string.
103
+ - For uint8 list: Convert the bytes into a list of integers.
104
+ - For raw bytes: Return as-is.
105
+
106
+ Args:
107
+ private_key_bytes (bytes): The private key in byte format.
108
+ output_format (str): The format to return ('base58', 'list', 'bytes').
109
+
110
+ Returns:
111
+ The private key in the requested format.
112
+
113
+ Raises:
114
+ ValueError: If the output_format is not recognized or the private key length is invalid.
115
+ """
116
+ if not isinstance (private_key_bytes , bytes ):
117
+ raise ValueError ("Expected the private key in bytes." )
118
+
119
+ if len (private_key_bytes ) != 32 :
120
+ raise ValueError ("Solana private key must be exactly 32 bytes long." )
121
+
122
+ if output_format == "base58" :
123
+ return base58 .b58encode (private_key_bytes ).decode ("utf-8" )
124
+
125
+ elif output_format == "list" :
126
+ return list (private_key_bytes )
127
+
128
+ elif output_format == "bytes" :
129
+ return private_key_bytes
130
+
131
+ else :
132
+ raise ValueError ("Invalid output format. Choose 'base58', 'list', or 'bytes'." )
133
+
134
+
135
+ def parse_private_key (private_key : Union [str , List [int ], bytes ]) -> bytes :
136
+ """
137
+ Parse the private key which could be either:
138
+ - a base58-encoded string (which may contain both private and public key)
139
+ - a list of uint8 integers (which may contain both private and public key)
140
+ - a byte array (exactly 32 bytes)
141
+
142
+ Returns:
143
+ bytes: The private key in byte format (32 bytes).
144
+
145
+ Raises:
146
+ ValueError: If the private key format is invalid or the length is incorrect.
147
+ """
148
+ # If the private key is already in byte format
149
+ if isinstance (private_key , bytes ):
150
+ if len (private_key ) != 32 :
151
+ raise ValueError ("The private key in bytes must be exactly 32 bytes long." )
152
+ return private_key
153
+
154
+ # If the private key is a base58-encoded string
155
+ elif isinstance (private_key , str ):
156
+ try :
157
+ decoded_key = base58 .b58decode (private_key )
158
+ if len (decoded_key ) not in [32 , 64 ]:
159
+ raise ValueError (
160
+ "The base58 decoded private key must be either 32 or 64 bytes long."
161
+ )
162
+ return decoded_key [:32 ]
163
+ except Exception as e :
164
+ raise ValueError (f"Invalid base58 encoded private key: { e } " )
165
+
166
+ # If the private key is a list of uint8 integers
167
+ elif isinstance (private_key , list ):
168
+ if all (isinstance (i , int ) and 0 <= i <= 255 for i in private_key ):
169
+ byte_key = bytes (private_key )
170
+ if len (byte_key ) < 32 :
171
+ raise ValueError ("The uint8 array must contain at least 32 elements." )
172
+ return byte_key [:32 ] # Take the first 32 bytes (private key)
173
+ else :
174
+ raise ValueError (
175
+ "Invalid uint8 array, must contain integers between 0 and 255."
176
+ )
177
+
178
+ else :
179
+ raise ValueError (
180
+ "Unsupported private key format. Must be a base58 string, bytes, or a list of uint8 integers."
181
+ )
0 commit comments