SolanaのkeypairファイルからPubKeyとPriKeyをBase58で復元する方法

参考:(というかほぼパクリ

solana-keygen で作られるkeypairファイルからPublicKeyとPrivateKeyを復元する手順

keypairファイルには64の整数値からなる配列がjson形式で格納される

最初の32要素はprivate keyを、後の32要素はpublic keyを表す

これをhexでパックしてbase58に変換するとよくみるやつになる

以下サイトからコピペ

module Base58 @chars = %w[ 1 2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z a b c d e f g h i j k m n o p q r s t u v w x y z ] @base = @chars.length def self.encode(hex) i = hex.to_i(16) buffer = String.new while i > 0 remainder = i % @base i = i / @base buffer = @chars[remainder] + buffer end # add '1's to the start based on number of leading bytes of zeros leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2 ("1"*leading_zero_bytes) + buffer end def self.decode(base58) total = 0 # integer to hold conversion to decimal # run through each character base58.reverse.each_char.with_index do |char, i| char_i = @chars.index(char) # get the index number for this character value = (58**i) * char_i # work out how many 58s this character represents total = total + value # add to total end # convert this integer to hex hex = total.to_s(16) # add leading 00s for every leading 1 leading_1s = (base58.match(/^([1]+)/) ? $1 : '').size ("00"*leading_1s) + hex end end
base58.rb
require_relative "base58" def bytes_to_base58(bytes) hex = bytes.pack("C*").unpack("H*").first Base58.encode(hex) end keypair_bytes = [xx,xx,xx,...,xx] private_key_bytes = keypair_bytes[0, 32] public_key_bytes = keypair_bytes[32..-1] puts "Keypair:", bytes_to_base58(keypair_bytes) puts "\nPublic Key:", bytes_to_base58(public_key_bytes) puts "\nPrivate Key:", bytes_to_base58(private_key_bytes)
keypair.rb

実行

$ ruby keypair.rb Keypair: XKN2tHYgZi5kPfkyZHmXnMxqp1CH8xsr8uZhYGBWAa9b4UQsoggsdtbkvp6U1aZQV8rvt795KgopQzXGoJhUsAt Public Key: 8hF4CySCPaXVE6txq4mFmowGsfuwXSsa4F1jbU7FXPVW Private Key: 2m4BDubAwRXNTfspfd6MZMFBA3VeMq6whe68Af3di8y6
この鍵はどうてもいいやつです

goのSDK使う時、key pairをファイルから読むのが面倒なのでAccountFromBase58メソッド使ってコマンド引数で与えたかったので調べたけど、このメソッドはどうやらprivate keyのBase58じゃなくてkeypair本体のBase58を読むらしいのでここまではしなくてよかった

keypairファイル → byte → hex → base58 すればok

得られたbase58を引数で指定して実行すれば楽にFeePayerを指定できる

以下実装例

// 抜粋 var ( FeePayerKeyPairBase58 = flag.String("feepayer", "", "keypair no base 58") ) var feePayerAccount types.Account func init() { flag.Parse() fe, err := types.AccountFromBase58(*FeePayerKeyPairBase58) if err != nil { log.Fatalf("load fee payer, err: %v", err) } fmt.Println("💰 Fee payer:", fe.PublicKey.ToBase58()) feePayerAccount = fe }
$ ./main -feepayer XKN2tHYgZi5kPfkyZHmXnMxqp1CH8xsr8uZhYGBWAa9b4UQsoggsdtbkvp6U1aZQV8rvt795KgopQzXGoJhUsAt

適当に書いたからこれが最適解かは知らん

ソースコード完全非公開ならハードコードでもいいけど汎用性考えたら...

というかBase58の処理書かされたけど多分Bitcoin関係でライブラリ探せばあると思う

bitcoinrbとかに入ってそう