Creating a Radix Wallet Address for Development Purposes
Radix Wallets are created using Elliptic Curve Cryptography (ECC) to generate a Private/Public Key pair. Specifically, we use an Elliptic Curve Digital Signature Algorithm (ECDSA) with the curve parameters defined by SECP256K1.
1. Install Dependencies
Install the following libraries that will be used to create the key pair and then convert them into a Radix Wallet Address:
pip install ecdsa
pip install bech32
2. Create Private Key
The following snippet generates a Private Key using the ECDSA algorithm with the SECP256k1 curve parameters. By default, the generate function uses os.urandom
as a cryptographically secure source of entropy (randomness).
import ecdsa
import bech32
# Create the Private Key
private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
private_key_bytes = private_key.to_string()
print("Private Key: ", private_key_bytes.hex())
Save the Private Key value as you will need it to sign transactions later.
3. Generate Public Key from Private Key
Append the following snippet to the code above to generate the Public Key that corresponds to your Private Key:
# Generate Public Key from Private Key
verifying_key = private_key.get_verifying_key()
public_key_compressed_bytes = verifying_key.to_string("compressed")
print("Public Key (Compressed): ", public_key_compressed_bytes.hex())
3.1 Compressed Public Keys
The Public Key is made up of two co-ordinates (x, y) on the SECP256k1 curve. These x and y co-ordinates are generated from the Private Key and are 32 bytes each. For example:
x: f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63
y: 4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1
The format of a “Full” Public Key consists of prefixing the Public Key with a byte value of “04” and then appending the x and y values to create a 65 byte (1 byte prefix + 32 byte x +32 byte y) value:
Full Public Key: 04f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d634cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1
We can reduce the size of the public key without losing any information by “compressing” public key co-ordinates as follows:
- If the value of the y co-ordinate is even, then use a byte value of “02” as a prefix
- If the value of the y co-ordinate is odd, then use a byte value of “03” as a prefix
- The compressed public key is: prefix + x co-ordinate
Below is an example of converting our public key into a compressed public key using the rules above:
# y: 4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1
# y is odd so our prefix will be 03
# Prepend 03 to x to create our 33 byte compressed public key:
Compressed Public Key: 03f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63
The compressed public key can be converted back to a full public key using some simple maths (see references below for more details)
4. Generate Radix Wallet Address from Public Key
4.1 Convert Compressed Public Key to Radix Engine Address
Radix converts the Compressed Public Key into a Radix Engine Address. The Radix Engine Address is a “1 to 34 byte array describing a resource or component in the Radix Engine”. The first byte of the Radix Engine Address describes the type of address:
- 0x01 - Native Token (XRD)
- 0x03 - Hashed Key + Nonce (User created Tokens)
- 0x04 - Public Key
# Convert Compressed Public Key into a Radix Engine Address
readdr_bytes = b"\x04" + public_key_compressed_bytes
4.2 Convert Radix Engine Address into Bech32 Encoded String
Next, we convert the Radix Engine Address into a Bech32 encoded string. Bech32 is standard for creating an encoded base 32, checksummed address format. A Bech32 address consists of the following parts:
- A human readable part (HRP) which conveys the type of data. Radix mainnet uses rdx for the mainnet human readable part.
- A separator. Always “1”
- A data part which is always at least 6 alphanumeric characters long excluding “1”, “b”, “i” and “o”. The last 6 characters of the data form a checksum using a BCH Code and contain no information.
The BCH checksum algorithm guarantees detection of any error affecting at most 4 characters and has a less than 1 in 1 billion chance of failing to detect more errors. BCH can also identify where in an address the typos were made.
The python bech32 library we use is a reference implementation and is used to create Bitcoin segwit addresses. The Radix Wallet Address uses a modified version of the Bitcoin BIP-0173 Segwit Address Format so we need to use some lower level functions in the python bech32 library to get the right output format.
Append the following snippet to the code above to convert the Radix Engine Address into the Bech32 encoded Radix Wallet Address format:
# Convert Radix Engine Address to Bech32 Radix Wallet Address
readdr_bytes5 = bech32.convertbits(readdr_bytes, 8, 5)
wallet_address = bech32.bech32_encode("rdx", readdr_bytes5)
print("Wallet Address: ", wallet_address)
You now have all 3 values required to perform transactions on the Radix Ledger using the RPC API:
- Private Key
- Compressed Public Key
- Radix Wallet Address
5. Complete Code Snippet
import ecdsa
import bech32
# Create the Private Key
private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
private_key_bytes = private_key.to_string()
print("Private Key: ", private_key_bytes.hex())
# Generate Public Key from Private Key
verifying_key = private_key.get_verifying_key()
public_key_compressed_bytes = verifying_key.to_string("compressed")
print("Public Key (Compressed): ", public_key_compressed_bytes.hex())
# Convert Compressed Public Key into a Radix Engine Address
readdr_bytes = b"\x04" + public_key_compressed_bytes
# Convert Radix Engine Address to Bech32 Radix Wallet Address
readdr_bytes5 = bech32.convertbits(readdr_bytes, 8, 5)
wallet_address = bech32.bech32_encode("rdx", readdr_bytes5)
print("Wallet Address: ", wallet_address)
References
- SECP256k1 Curve: https://en.bitcoin.it/wiki/Secp256k1
- Public Keys: https://learnmeabitcoin.com/technical/public-key
- Bech32 Specification: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
- BCH Code: https://en.wikipedia.org/wiki/BCH_code
This work by RadixPool.com is licensed under a Creative Commons Attribution 4.0 International License.