11import json
22from pathlib import Path
3- from typing import Dict , Optional , Union
3+ from typing import Dict , List , Optional , Union
44
55import base58
66from nacl .exceptions import BadSignatureError as NaclBadSignatureError
@@ -22,7 +22,7 @@ class SOLAccount(BaseAccount):
2222 _private_key : PrivateKey
2323
2424 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 ))
2626 self ._signing_key = SigningKey (self .private_key )
2727 self ._private_key = self ._signing_key .to_curve25519_private_key ()
2828
@@ -79,7 +79,7 @@ def verify_signature(
7979 public_key: The public key to use for verification. Can be a base58 encoded string or bytes.
8080 message: The message to verify. Can be an utf-8 string or bytes.
8181 Raises:
82- BadSignatureError: If the signature is invalid.
82+ BadSignatureError: If the signature is invalid.!
8383 """
8484 if isinstance (signature , str ):
8585 signature = base58 .b58decode (signature )
@@ -91,3 +91,91 @@ def verify_signature(
9191 VerifyKey (public_key ).verify (message , signature )
9292 except NaclBadSignatureError as e :
9393 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