Splitting a Solana Keypair into Public and Private Keys

In this guide we’re going to dive into how to take a Solana keypair and break it its corresponding public and private keys.

Lets go ahead and use the Solana CLI to generate a new wallet with the keypair stored in a File System Wallet:

$ solana-keygen new --outfile ~/my-solana-wallet/demo.json
      
Generating a new keypair
For added security, enter a BIP39 passphrase
NOTE! This passphrase improves security of the recovery seed phrase NOT the
keypair file itself, which is stored as insecure plain text
BIP39 Passphrase (empty for none): 
Wrote new keypair to /Users/matt/my-solana-wallet/demo.json
=============================================================================
pubkey: HAE1oNnc3XBmPudphRcHhyCvGShtgDYtZVzx2MocKEr1
=============================================================================
Save this seed phrase and your BIP39 passphrase to recover your new keypair:
favorite maid bind piece social father neutral over unusual tank brother code
=============================================================================

This command generates a JSON file containing the keypair:

$ cat ~/my-solana-wallet/demo.json

[4,182,130,247,119,117,227,207,112,73,170,126,222,197,244,99,215,107,255,202,33,43,36,17,104,111,157,246,196,192,174,95,240,23,238,206,118,215,154,238,229,96,11,37,156,123,51,223,5,231,17,117,86,136,103,14,75,95,175,132,148,54,1,46]  

This is an array containing 64 values:

The first 32 values represent the private key:

private_key_bytes = [4, 182, 130, 247, 119, 117, 227, 207, 112, 73, 170, 126, 222, 197, 244, 99, 215, 107, 255, 202, 33, 43, 36, 17, 104, 111, 157, 246, 196, 192, 174, 95]

The second 32 values represent the public key:

public_key_bytes = [240, 23, 238, 206, 118, 215, 154, 238, 229, 96, 11, 37, 156, 123, 51, 223, 5, 231, 17, 117, 86, 136, 103, 14, 75, 95, 175, 132, 148, 54, 1, 46]

While this is the public key, it’s not in the same format as the public key displayed by the Solana CLI above. In order to format it that way, we need to convert this array of integer values into base 58.

In Ruby we’ll first convert the array to hex (base 16):

public_key_hex = public_key_bytes.pack("C*").unpack("H*").first

And then we can use a base 58 script to convert the hex into the base 58:

public_key = Base58.encode(public_key_hex)

And that gives us the same public key aka wallet address that we saw earlier in the Solana CLI output:

HAE1oNnc3XBmPudphRcHhyCvGShtgDYtZVzx2MocKEr1

We can follow the same process to get the base 58 private key:

KQ3cGFBdjJuRsB7U1K4to6cTGBPhgukqPgsi5pryr8v

And also the base 58 keypair (which is the same thing you would get if you clicked the Export Private Key button in a Phantom Wallet, but note that it’s not actually the private key, it’s the keypair with both the private and public key – I suspect they call it that to make it clear to users that it includes the private key):

6Tyktf6mEqUMEKm2ZpLn3srEwk9zsT5jiE54EgPgToikMFYww1LGFUXgwgr6hvc9CikpaNaBH2vmkmqN3Usrxpd

Try it yourself

1. Create a new folder

2. Create a file called base58.rb and copy the base 58 Ruby script from this tutorial

3. Create another file named like keypair.rb and paste in the following script:

require_relative "base58"
def bytes_to_base58(bytes)
hex = bytes.pack("C*").unpack("H*").first
Base58.encode(hex)
end
keypair_bytes = [4,182,130,247,119,117,227,207,112,73,170,126,222,197,244,99,215,107,255,202,33,43,36,17,104,111,157,246,196,192,174,95,240,23,238,206,118,215,154,238,229,96,11,37,156,123,51,223,5,231,17,117,86,136,103,14,75,95,175,132,148,54,1,46]
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)
view raw keypair.rb hosted with ❤ by GitHub

4. Replace the content of keypair_bytes with the value from your File System Wallet (you can use solana config get to get the path to your keypair, then use the cat command like above to get the content).

5. Then from the command line simply run ruby keypair.rb to run the script:

$ ruby keypair.rb 
 
Keypair:
6Tyktf6mEqUMEKm2ZpLn3srEwk9zsT5jiE54EgPgToikMFYww1LGFUXgwgr6hvc9CikpaNaBH2vmkmqN3Usrxpd

Public Key:
HAE1oNnc3XBmPudphRcHhyCvGShtgDYtZVzx2MocKEr1

Private Key:
KQ3cGFBdjJuRsB7U1K4to6cTGBPhgukqPgsi5pryr8v

Starting with a Base 58 Keypair

You can follow a similar process to take a base 58 keypair (like you would get from Export Private Key in a Phantom wallet) to derive the public and private keys:

require_relative "base58"
def bytes_to_base58(bytes)
hex = bytes.pack("C*").unpack("H*").first
Base58.encode(hex)
end
keypair = "6Tyktf6mEqUMEKm2ZpLn3srEwk9zsT5jiE54EgPgToikMFYww1LGFUXgwgr6hvc9CikpaNaBH2vmkmqN3Usrxpd"
keypair_hex = Base58.decode(keypair).rjust(128, "0")
keypair_bytes = [keypair_hex].pack('H*').bytes.to_a
private_key_bytes = keypair_bytes[0, 32]
public_key_bytes = keypair_bytes[32..-1]
puts "Public Key:", bytes_to_base58(public_key_bytes)
puts "\nPrivate Key:", bytes_to_base58(private_key_bytes)
view raw keypair58.rb hosted with ❤ by GitHub
$ ruby keypair58.rb

Public Key:
HAE1oNnc3XBmPudphRcHhyCvGShtgDYtZVzx2MocKEr1

Private Key:
KQ3cGFBdjJuRsB7U1K4to6cTGBPhgukqPgsi5pryr8v

Using a Phantom Wallet Address with the Solana CLI

I’m learning about Solana and wanted to try accessing the address I set up with Phantom via the Solana CLI.

For anyone Googling how to accomplish this, here are the steps I used:

Install the Solana CLI

First you’ll need to install the Solana CLI.

Note that the installation script assumed I was using Bash and added the Solana CLI to Bash’s PATH variable, but my Mac is using the Z Shell (zsh), so I had to manually add the Solana CLI to the Z Shell PATH variable:

vi ~/.zshrc 
export PATH="/Users/matt/.local/share/solana/install/active_release/bin:$PATH"

Generate a File System Wallet

From the command line, run:

$ solana-keygen recover 'prompt:?key=0/0' --outfile ~/.config/solana/id.json

This will prompt for your Secret Recovery Phrase (which you can access through the Phantom Wallet’s settings). Enter it and when prompted to continue enter “y” to generate the local keypair file:

[recover] seed phrase: 
[recover] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue: 
Recovered pubkey `abc123`. Continue? (y/n): y
Wrote recovered keypair to /Users/matt/.config/solana/id.json

If all went well you should be able to run a command like solana balance to access the account balance:

$ solana balance

0.123456789 SOL

You can also confirm that the file you generated above maps back to the public key associated with your Phantom wallet:

$ solana-keygen pubkey

abc123

Or verify that the public key is correctly associated with your local private key:

$ solana-keygen verify abc123

Verification for public key: abc123: Success

Friday Updates: New Homepage, Focusing on Professionals, Data Intake Form, Acquisitions Anonymous, Startup

Photo by Manuel Venturini

Hey friends, it’s been a few weeks since my last update. I’m probably not going to do these weekly right now, but hopefully can still find time for one or two a month going forward.

Preceden

New homepage

For years now Preceden’s homepage has had a sign up form above the fold:

There was a time when the sign up page was separate, but I A/B tested it back in like 2014 and putting the sign up form on the homepage almost doubled sign ups, and so that’s where it’s remained ever since.

There was an example timeline below the fold and there’s also a whole section of the site with examples, but a large % of users signed up without actually seeing the type of timelines that Preceden can create. And as a result, a lot bail immediately after signing up, I suspect because there’s some misalignment between what type of timeline they expect vs reality.

To remedy this, Milan (the front-end designer I work with) and I redesigned the homepage to ensure everyone visiting has a better idea of what Preceden is capable of:

The tradeoff is that the homepage to sign up conversion rate winds up dropping, but I’m alright with that because new sign ups are a lot higher quality now and I’m not wasting the time of people that Preceden isn’t a good fit for.

The day after this change there was a huge spike in sign ups – about double compared to the day prior. My optimistic take on it at the time was that the homepage was resonating with a lot more visitors which was leading to more sign ups than in the past. But… after digging in it turned out that a large % of the sign ups were bots. Whomp whomp. I suspect that there are bots that look for /signups paths, fill out the form with garbage content, and then look for more forms in-app to spam. Preceden’s in-app experience doesn’t lend itself well to bots so all of the bots gave up immediately after signing up, but it still wound up inflating sign ups and hurting a bunch of post-sign up conversion rates. I was able to prevent the bot sign ups by looking at a few factors like whether they had keystrokes on the sign up form (these bots did not) which dropped sign ups back down to a more realistic level.

Focusing on professionals

When people sign up for Preceden, I ask them what they plan to use it for. Historically the options were Professional Use, Personal Use, School, and Teaching. Preceden has been a general purpose timeline maker tool and these are the groups that virtually everyone falls into. But… being general purpose is tough. It’s difficult to focus the copy on one audience, it’s difficult to focus the product, etc. I’ve been hesitant to focus on one because no single group dominates revenue. For example, people who choose Professional Use have made up about 5% of sign ups but 40% of revenue. The risk of focusing on them is that you execute on it poorly and put the other 60% of revenue at risk.

But… after years of waffling on this issue, that’s the direction I’m now headed: focusing on professionals. They are great customers and there’s a lot of long term upside if I can pull it off, even though I might wind up seeing lower revenue in the short term.

Practically speaking, it means things like:

  • Removing School and Teaching from the sign up form options
  • Focusing the examples on professionals
  • Focusing the copy on project planning and whatnot
  • Reworking the plans which have historically included a low-cost Student plan

We’ll see how it all turns out, but I’m optimistic and excited to work on it.

Help Scout

Michael, the new data lead who joined in May, set up a data request intake form which has gone a long way towards organizing our day-to-day data work at Help Scout. Here’s the current version:

These get sent to an Asana board with lists that we can move the tasks around as needed: Inbox, Backlog, Blocked, In Progress, and Complete.

Should have set something up like this a long time ago.

What I’m listening to

What I’m watching

Startup on Netflix:

Take care y’all.

Friday Updates: Back from Paternity Leave

Photo by Sergey Shmidt

I took it easy for most of June to help out with Owen and generally try to make things as easy as possible for my wife. We now have 4 kids – ages 6, 5, 3, and the newborn, which means there’s rarely a dull moment in the Mazur household.

Preceden

I put some time into Preceden during the break, knocking out a few small product improvements here and there.

One of these included integrating Headway, an in-app changelog notification widget that lets me keep users informed about recent updates to the Preceden:

In addition to being able to read them directly in the app, Headway generates a public page where anyone can follow the changes. I also hooked Headway up to Preceden’s long-neglected Twitter account where it shares updates when I publish them:

Recent updates include:

And yes, I do need to resume marketing initiatives one of these days.

Help Scout

I took June completely off from Help Scout. As a contractor, it’s not paid time off, but I put in extra hours in May in preparation for the time off in June so thankfully didn’t have to forgo any income to take the time off.

With the hire of Michael, the new Data Lead, in May, my work at Help Scout is changing: I have more bandwidth to tackle bigger data projects because Michael has taken on a lot of the other day to day responsibilities.

The big project I’m starting is building out a Likelihood to Close Score that uses machine learning to help us estimate the probability that a trial will go onto become a customer. It’s requiring picking up some new skills because it’s one thing to build a scikit-learn model locally in a Jupyter Notebook, another thing to get a model in production and have the score available in our data warehouse to use in Looker and other analyses. I’ll write a post down the road sharing how it all works, assuming I can figure it out.

What I’m listening to

Lots of podcasts thanks to some long car rides during my break + listening in the morning during yoga:

  • My First Million with Sam Parr and Shaan Puri
  • Lex Fridman, a polymath who interviews lots of brilliant folks in technology, science, and entrepreneurship. I’ve listened to his interviews with Vitalik Buterin about Ethereum 2.0, Bryan Johnson about building brain-computer interfaces at Kernel, Sam Harris about consciousness, Silvio Micali about Algorand, Jason Calacanis about angel investing, and Clara Sousa-Silva about her work detecting phosphene on Venus which might be a sign of life there.
  • Indie Hackers with Courtland Allen
  • Art of Product with Ben Orenstein and Derrick Reimer

What I’m reading

Hope all is well with you all ๐Ÿ‘‹.