TallyBox Tutorial - Wallet Creation

by shahiN Noursalehi

You are here: Home / Toturials / Tallybox Wallet Creation - Pseudo Edition

Note: This tutorial is structured to be AI-Friendly. An AI can generate code in any programming language based on the content of this URL, thanks to its clear steps, pseudo-code, and examples.

Creating a TallyBox Wallet

This tutorial guides tech-savvy users through the process of creating a secure TallyBox wallet using the secp256r1 elliptic curve. You'll generate a key pair, derive a unique wallet address, verify its integrity, and provision it for use in the TallyBox ecosystem, ensuring compatibility with TallyBox's cryptographic standards. The focus is on the algorithms and math behind each step, making it easy to implement in any programming language. Pseudo-code is provided for complex steps to aid implementation without libraries.

Step 1: Generate a Private-Public Key Pair

Use the secp256r1 elliptic curve (also known as P-256) to generate a key pair. This curve is defined by the equation y² = x³ + ax + b over a finite field, where a and b are specific constants, and the field size is a 256-bit prime (P). The process involves:

The private key must be kept secret, while the public key (X, Y coordinates) is used in subsequent steps.

Secp256r1 Curve Parameters:

P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF  // Prime field
a = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC  // Curve coefficient
b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B  // Curve coefficient
Gx = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296  // Base point X
Gy = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5  // Base point Y
n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551  // Order of the curve
                


Example Process:

Private Key: 7a8d26a42f45ecc68bc9d9ad2de9e4868429de2b185ab7e023f93845c58c4fa1

Public Key (Uncompressed):

X: 252df02599b4560df18cb5e7486769303c0ec0dcb0f64a5a980e41feba7d593f

Y: 7020405e0700461be964eaf159e3e20bd9aee2fda2f93b0c6ef03ee63876db47

References:
SEC 2: Recommended Elliptic Curve Domain Parameters (secp256r1)
Elliptic Curve Cryptography (Wikipedia)

Step 2: Compress and Encode the Public Key

Compress the public key to reduce its size, then encode it in Base58. The process involves:

Pseudo-Code: Compress Public Key

FUNCTION compress_public_key(X, Y):
    parity = Y % 2
    IF parity == 1 THEN
        suffix = '1'
    ELSE
        suffix = '2'
    END IF
    compressed_key = X + '*' + suffix
    RETURN compressed_key
END FUNCTION
                


Pseudo-Code: Base58 Encode

FUNCTION base58_encode(bytes):
    alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    value = bytes_to_integer(bytes)  // Convert byte array to big integer (unsigned)
    result = ''
    WHILE value > 0:
        remainder = value % 58
        result = alphabet[remainder] + result
        value = value / 58  // Integer division
    END WHILE
    // Handle leading zeros in the byte array
    FOR each byte in bytes:
        IF byte == 0 THEN
            result = '1' + result
        ELSE
            BREAK
        END IF
    END FOR
    RETURN result
END FUNCTION
                


Example Process:

Compressed Key: 252df02599b4560df18cb5e7486769303c0ec0dcb0f64a5a980e41feba7d593f*1

Base58 Compressed Public Key: 3W8iLTuAjbf9d1ih4RCi7Aat6keKxs72SNynZ1A269MY*1

References:
Base58 Encoding (Wikipedia)
Compressed Public Key Explanation (Bitcoin Stack Exchange)

Step 3: Derive the TallyBox Wallet Address

Derive a unique wallet address from the Base58-encoded public key. The process involves:

Note: MD5 is outdated and insecure for cryptographic purposes. However, in TallyBox's wallet address structure, we use it solely to detect copy-paste errors, not for security-critical operations.

Example Process:

Base58 Compressed Public Key: 3W8iLTuAjbf9d1ih4RCi7Aat6keKxs72SNynZ1A269MY*1

SHA-256 Hash: 5e3df94169f3d82b9b67d93acbc288a42c9812ced307297f78ed3058d338b1e4

Raw Wallet (Bigint): 42626905736173508565770948203518737897276237144762802425237770121056689369572

Base58 Encoded: 7Lt8jmf3GNWCJc2K5bU7aAS5gqSbDYnY5UVshnJVHEJP

MD5 Hash: a01d317e6c52656bb188a55736dc5aab

Checksum: boxBa01d317e6c5

Final Wallet Address: boxBa01d317e6c57Lt8jmf3GNWCJc2K5bU7aAS5gqSbDYnY5UVshnJVHEJP

References:
SHA-256 Algorithm (Wikipedia)
MD5 Algorithm (Wikipedia)
Base58 Encoding (Wikipedia)

Step 4: Verify the Key Pair Integrity

Verify the key pair to ensure it is valid for TallyBox transactions. The process involves:

Note: The ECDSA signing process must comply with RFC 6979 to ensure deterministic signatures, enhancing security and reproducibility.

Example Process:

Message Signed: "TallyBox, a tool for curious minds.."

Signature (Base64): MEYCIQD6BLlP29AzfKK/SPyuMdVYrWzn/wQElsdkVF+ewvBgDQIhANy4lgejq9JChhQM/9PWyxfLKJYxRz4SWcoBak468i5s

Base58 Compressed Public Key: 3W8iLTuAjbf9d1ih4RCi7Aat6keKxs72SNynZ1A269MY*1

Decompressed Public Key (X*Y): 252df02599b4560df18cb5e7486769303c0ec0dcb0f64a5a980e41feba7d593f*7020405e0700461be964eaf159e3e20bd9aee2fda2f93b0c6ef03ee63876db47

Signature Verification Result: Valid

References:
ECDSA Algorithm (Wikipedia)
SEC 2: Recommended Elliptic Curve Domain Parameters (secp256r1)
RFC 6979: Deterministic Usage of DSA and ECDSA

Step 5: Provision the TallyBox Wallet

Provision the wallet by securely storing its data. The process involves:

Note: Ensure the private key and XML file are stored securely (e.g., on an encrypted drive) to prevent unauthorized access.

Special AES-256-CBC with Custom Padding

TallyBox uses a unique AES-256-CBC encryption algorithm with custom padding to secure the private key. The algorithm derives the key, IV, and salt from a 64-character hex secret key (SHA-256 of wallet_name~password~wallet_address). Random padding is added around the plaintext for enhanced security. The configuration is:

  • Secret Key: A 64-character hex string (32 bytes), split into:
    • Password: First 32 hex chars (16 bytes, ASCII-encoded).
    • IV: Next 16 hex chars (8 bytes, ASCII-encoded, 16 bytes as bytes).
    • Salt: Last 16 hex chars (8 bytes, ASCII-encoded).
  • Key Derivation: PBKDF2 with SHA-256, 3 iterations, 32-byte output, using password and salt.
  • Custom Padding: Random string (0–99 chars, a-zA-Z) + '|' + plaintext (64-char hex private key) + '|' + random string (0–99 chars, a-zA-Z), followed by PKCS#7 padding.
  • Output: Base64-encoded ciphertext (no IV prepended).

Pseudo-Code: AES-256-CBC Encrypt with Custom Padding

FUNCTION aes256_cbc_encrypt_custom(data, secret):
    IF length(secret) < 64 OR NOT is_hex(secret) THEN
        THROW "Secret must be a 64-char hex string"
    END IF
    password = secret[0:32]  // First 32 hex chars (ASCII)
    iv = secret[32:48]       // Next 16 hex chars (ASCII)
    salt = secret[48:64]     // Last 16 hex chars (ASCII)
    key = PBKDF2_HMAC_SHA256(password, salt, iterations=3, output_bytes=32)
    left_padding_size = random_integer(0, 99)
    left_padding = random_string(left_padding_size, 'a-zA-Z')
    right_padding_size = random_integer(0, 99)
    right_padding = random_string(right_padding_size, 'a-zA-Z')
    padded_data = left_padding + '|' + data + '|' + right_padding
    padding_length = 16 - (length(padded_data) % 16)
    padded_data = padded_data + (padding_length as byte) * padding_length  // PKCS#7
    cipher = initialize_aes256_cbc_encrypt(key, iv)
    ciphertext = cipher.encrypt(padded_data)
    base64_result = base64_encode(ciphertext)
    RETURN base64_result
END FUNCTION
                    


Pseudo-Code: AES-256-CBC Decrypt with Custom Padding

FUNCTION aes256_cbc_decrypt_custom(base64_ciphertext, secret):
    IF length(secret) < 64 OR NOT is_hex(secret) THEN
        THROW "Secret must be a 64-char hex string"
    END IF
    ciphertext = base64_decode(base64_ciphertext.replace('\n', ''))  // Strip newlines
    password = secret[0:32]  // First 32 hex chars (ASCII)
    iv = secret[32:48]       // Next 16 hex chars (ASCII)
    salt = secret[48:64]     // Last 16 hex chars (ASCII)
    key = PBKDF2_HMAC_SHA256(password, salt, iterations=3, output_bytes=32)
    cipher = initialize_aes256_cbc_decrypt(key, iv)
    padded_data = cipher.decrypt(ciphertext)
    padding_length = padded_data[-1]
    IF padding_length > 16 OR padding_length == 0 THEN
        THROW "Invalid PKCS#7 padding"
    END IF
    padded_data = padded_data[:-padding_length]  // Remove PKCS#7 padding
    padded_text = padded_data.decode('utf-8')
    parts = padded_text.split('|')
    IF length(parts) != 3 THEN
        THROW "Invalid padding format: expected 'left|data|right'"
    END IF
    plaintext = parts[1]
    IF NOT is_hex(plaintext) OR length(plaintext) != 64 THEN
        THROW "Decrypted private key must be a 64-char hex string"
    END IF
    RETURN plaintext
END FUNCTION
                    


Example Process:

Original Private Key (hex): 7a8d26a42f45ecc68bc9d9ad2de9e4868429de2b185ab7e023f93845c58c4fa1

Key Components (pre-SHA-256): shahin~11~boxBa01d317e6c57Lt8jmf3GNWCJc2K5bU7aAS5gqSbDYnY5UVshnJVHEJP

Local Key (SHA-256): 7e9b4699f7d3eea878f51a9d4e238922116cccc558b15f2db257d92a9779becc

Encrypted Private Key (Base64): Lu8xEpnACOtVrmZxRt7I2m7Zc5pZI8sxIGhXV6FqwN6N2VG8yt4jof5c0Xo5slF+VyOLORhls2auG27Xmjd20Z/9YiBZ2E5ePFsQV7ZkeqKFZa+k5IrOHGjDcyJtiJt22zAzOaSvyTFFGRHwDGI1FCJ5BppBvYkoGhro9MxHp3MVS7eW2N3z2NEQV2Gxm+IErv0ExkxfesyXqw/kTwk2qHBuTUtKRgkOY8RCAPPkNglOjfo4ct+YCdkzoIS/Ww6xatWmAUA6bhtxK2q3vZly1iteNAa+Uz0Pyn166f7Y90cCGJPINc5x7WGcolqPeWf5

Decrypted Private Key (hex): 7a8d26a42f45ecc68bc9d9ad2de9e4868429de2b185ab7e023f93845c58c4fa1

Verification Result: Verified


Example Output:

References:
AES Encryption (Wikipedia)
SHA-256 Algorithm (Wikipedia)
XML Specification (W3C)

Acknowledgments

Special thanks to Grok, for its invaluable assistance in creating this TallyBox wallet creation tutorial.