Key Pairs

Accounts in Stellar are identified by a cryptographic key pair.

The public key, also known as the account id, can safely be shared with anybody. It is 52 characters long and begins with a G.

The private key, referred to as the secret seed, should be kept private & secure. It is also 52 characters long, but begins with an S.

For example, the following is a randomly generated account key pair. (This is an example only, do not use this.)

Account id:  GD2HMF3BKITMXISCPTU7VVTFXDY5WSQK4QNIUATNCXVKBNWZP7FWZOXG
Secret Seed: SDHXK2UNHTXVW2MZSOVOPYUKVXD3PEVKMNQZZGPODQMR67YTKWMOC732

The knowledge of a key pair does not imply that the account exists on any Stellar network. In other words, when you call KeyPair.random, this does not create an account. To do that, you need to issue a transaction that contains a CreateAccountOperation, as explained in Transacting.

There are actually two kinds of KeyPair objects in the SDK.

  • represents the public and secret components, and can be used for operations that require proof of the secret portion, such as transaction signing.
  • represents only the public component. This is used to refer to accounts other than your own, such as the counterparty of a payment.

As the account id can be derived from the secret seed, there is no object which models the secret seed without the account id.

The SDK provides several ways to create or resolve KeyPairs and PublicKeys.

Randomly

A random KeyPair is generated when you call KeyPair.random.

KeyPair.random

The chance of receiving a key pair that has been seen before is so miniscule that you might reasonably assume that any randomly generated pair is effectively unique.

By Key

If you know the secret seed (private key), then you can reconstitute the KeyPair.

// Provide the secret seed as a String
val keyPair = KeyPair.fromSecretSeed(
  "SDHXK2UNHTXVW2MZSOVOPYUKVXD3PEVKMNQZZGPODQMR67YTKWMOC732")

// or an Array[Char]
KeyPair.fromSecretSeed(
  "SDHXK2UNHTXVW2MZSOVOPYUKVXD3PEVKMNQZZGPODQMR67YTKWMOC732".toCharArray.toIndexedSeq)

// or a raw 32 byte seed
KeyPair.fromSecretSeed(
  Hex.decodeHex("1123740522f11bfef6b3671f51e159ccf589ccf8965262dd5f97d1721d383dd4")
)

If you only know the account id (public key), you can create the PublicKey.

val accountId = "GCXYKQF35XWATRB6AWDDV2Y322IFU2ACYYN5M2YB44IBWAIITQ4RYPXK"
val publicKey = KeyPair.fromAccountId(accountId)

By Passphrase

As a substitute for a valid secret seed, any passphrase can be used to deterministically derive a KeyPair.

val kp = KeyPair.fromPassphrase(
  "But, the Babel fish is a dead giveaway isn't it?"
)

By Federated Address

As a convenience, accounts may also be identified by a human-readable address known as a Federated Address. These are in the format NAME*DOMAIN.

Federated addresses can be resolved using the fromAddress method. Because the actual public key is retrieved from the network, this method returns a Future[PublicKey] and may fail.

val resolved: Future[PublicKey] = KeyPair.fromAddress("jem*keybase.io")

That’s all you need to know about KeyPairs. Continue reading to learn about how to inspect Stellar networks via Queries.

From a cryptographic seed phrase

Keys can be restored from a mnemonic phrase and, optionally, a password.

val keyPair = KeyPair.fromMnemonicPhrase(
  phrase = "cable spray genius state float twenty onion head street palace net private " +
    "method loan turn phrase state blanket interest dry amazing dress blast tube",
  passphrase = "p4ssphr4se".getBytes("UTF-8"))
keyPair.accountId mustEqual "GDAHPZ2NSYIIHZXM56Y36SBVTV5QKFIZGYMMBHOU53ETUSWTP62B63EQ"

Mnemonic phrases are available in Chinese (simplified & traditional), Czech, English, French, Italian, Japanese, Korean and Spanish. Additional languages can be implemented in clients as needed. See

val keyPair = KeyPair.fromMnemonicPhrase(
  phrase = "つぶす きそう かるい ようじ なまいき むさぼる あこがれる そっせん みせる しちょう " +
    "そんしつ まろやか しへい さわやか でんあつ めした せんとう だっきゃく ほっさ ひるやすみ " +
    "はさみ ようちえん おんだん えらい",
  wordList = JapaneseWords)
keyPair.accountId mustEqual "GDEIRKSGFKJCCXUQAM2KVUOAFV626NESTZ5Q4FRCUXTTYHK6RTN66TY2"

You can construct a new random mnemonic phrase with any supported language and 128-256 bits of entropy.

val mnemonic = Mnemonic.random(SpanishWords, entropyBits = 128)
val passphrase = new ByteString("perro salchicha".getBytes(UTF_8))
val keyPair = mnemonic.asRootKeyPair(passphrase)
KeyPair.fromMnemonic(mnemonic, passphrase, SpanishWords).accountId mustEqual keyPair.accountId

(If you wish to use your own source of entropy, rather than rely on the JVM, you can do that via the method Mnemonic.fromEntropy.)

More on mnemonics

Mnemonic phrases derive cryptographic seeds which are the the root of a vast tree of deterministic addresses. If you wish to do more than map a phrase to a KeyPair, then you should access the HDNode of the Mnemonic. From any node, you can derive the child nodes to any depth.

val mnemonic = Mnemonic.random(FrenchWords)
val passphrase = new ByteString("chien saucisse".getBytes(UTF_8))
val rootNode = mnemonic.asHDNode(passphrase)
val node = rootNode.deriveChild(33, 18, 193, 4)
node.privateKey mustEqual rootNode
  .deriveChild(33)
  .deriveChild(18)
  .deriveChild(193)
  .deriveChild(4)
  .privateKey

Note that the subtree of nodes 44/148/0 are dedicated to Stellar keys and can be accessed by the KeyPair deriving methods on both KeyPair and Mnemonic.