# Appendix : Debugging & Development Tools

### Introduction

This appendix provides practical tools and techniques for debugging cryptographic code in rippled, testing implementations, and developing new cryptographic features.

### Logging Cryptographic Operations

#### Enable Debug Logging

```
# Edit rippled.cfg
[rpc_startup]
{ "command": "log_level", "severity": "trace" }

# Or via RPC
./rippled log_level partition=Transaction severity=trace
```

#### Monitor Signature Verification

```
# Watch for signature verification
./rippled --conf rippled.cfg 2>&1 | grep -i "verify\|sign\|signature"

# Watch for failures
./rippled --conf rippled.cfg 2>&1 | grep -i "tefBAD_SIGNATURE\|temINVALID"
```

#### Custom Logging

```
// Add debug logging to crypto code
#include <ripple/beast/core/Journal.h>

void debugSign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
{
    JLOG(journal.trace()) << "Signing with key type: "
        << (publicKeyType(pk) == KeyType::ed25519 ? "ed25519" : "secp256k1");

    auto sig = sign(pk, sk, m);

    JLOG(journal.trace()) << "Signature size: " << sig.size();
    JLOG(journal.trace()) << "Signature (hex): " << strHex(sig);
}
```

### Standalone Mode for Testing

#### Start Standalone Node

```
# Start rippled in standalone mode (no network)
./rippled --standalone --conf rippled.cfg
```

#### Generate Test Accounts

```
# Generate new account with ed25519
./rippled wallet_propose ed25519

# Output:
# {
#   "account_id": "rN7n7otQDd6FczFgLdlqtyMVrn3LNU8B4C",
#   "key_type": "ed25519",
#   "master_key": "SNIT ARMY BOOM CALF ABLE ATOM CURE BARN FOWL ASIA HEAT TOUR",
#   "master_seed": "sn3nxiW7v8KXzPzAqzyHXbSSKNuN9",
#   "master_seed_hex": "DEDCE9CE67B451D852FD4E846FCDE31C",
#   "public_key": "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3",
#   "public_key_hex": "ED9434799226374926EDA3B54B1B461B4ABF7237962EEB1144C10A7CA6A9D32C64"
# }

# Generate with secp256k1
./rippled wallet_propose secp256k1
```

#### Test Transactions

```
# Submit test transaction
./rippled submit '{
  "tx_json": {
    "Account": "rN7n7otQDd6FczFgLdlqtyMVrn3LNU8B4C",
    "TransactionType": "Payment",
    "Destination": "rLHzPsX6oXkzU9w7fvQqJvGjzVtL5oJ47R",
    "Amount": "1000000"
  },
  "secret": "sn3nxiW7v8KXzPzAqzyHXbSSKNuN9",
  "key_type": "ed25519"
}'

# Manually close ledger
./rippled ledger_accept
```

### Debugging with GDB

#### Compile with Debug Symbols

```
# Build with debug info
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
```

#### Basic GDB Commands

```
# Start rippled in gdb
gdb --args ./rippled --standalone --conf rippled.cfg

# Common commands:
(gdb) break SecretKey.cpp:randomSecretKey  # Set breakpoint
(gdb) run                                   # Run program
(gdb) next                                  # Step over
(gdb) step                                  # Step into
(gdb) continue                              # Continue execution
(gdb) print sk                              # Print variable
(gdb) backtrace                             # Show call stack
```

#### Inspect Cryptographic Data

```
# Examine secret key bytes
(gdb) x/32xb &secretKey  # Display 32 bytes in hex

# Examine signature
(gdb) x/64xb signature.data()

# Print public key
(gdb) print /x publicKey

# Check key type
(gdb) print publicKeyType(pk)
```

#### Conditional Breakpoints

```
# Break only for ed25519 keys
(gdb) break sign if publicKeyType(pk) == KeyType::ed25519

# Break on signature verification failure
(gdb) break verify if $retval == false
```

### Memory Debugging with Valgrind

#### Check for Memory Leaks

```
# Run with valgrind
valgrind --leak-check=full --show-leak-kinds=all ./rippled --standalone

# Look for:
# - Definitely lost: Memory leaks
# - Possibly lost: Potential leaks
# - Still reachable: OK (cleanup at exit)
```

#### Check for Uninitialized Memory

```
# Detect uninitialized reads
valgrind --track-origins=yes ./rippled --standalone

# Look for:
# "Conditional jump or move depends on uninitialised value(s)"
# "Use of uninitialised value of size X"
```

### Unit Testing

#### Run Crypto Tests

```
# Run all tests
./rippled --unittest

# Run specific test suite
./rippled --unittest=ripple.protocol.SecretKey

# Run with specific algorithm
./rippled --unittest=ripple.protocol.SecretKey:Ed25519
```

#### Write Custom Tests

```
// From src/test/protocol/SecretKey_test.cpp

class SecretKey_test : public beast::unit_test::suite
{
public:
    void testRandomGeneration()
    {
        // Generate keys
        auto sk1 = randomSecretKey();
        auto sk2 = randomSecretKey();

        // Should be different
        expect(sk1 != sk2, "Random keys should be unique");

        // Should be correct size
        expect(sk1.size() == 32, "Secret key should be 32 bytes");
    }

    void testSigning()
    {
        auto [pk, sk] = randomKeyPair(KeyType::ed25519);
        std::vector<uint8_t> message{0x01, 0x02, 0x03};

        auto sig = sign(pk, sk, makeSlice(message));

        // Verify signature
        bool valid = verify(pk, makeSlice(message), sig, true);
        expect(valid, "Signature should verify");

        // Modify message
        message[0] = 0xFF;
        valid = verify(pk, makeSlice(message), sig, true);
        expect(!valid, "Modified message should not verify");
    }

    void run() override
    {
        testRandomGeneration();
        testSigning();
    }
};

BEAST_DEFINE_TESTSUITE(SecretKey, protocol, ripple);
```

### Benchmarking

#### Measure Performance

```
#include <chrono>

void benchmarkSigning()
{
    auto [pk, sk] = randomKeyPair(KeyType::ed25519);
    std::vector<uint8_t> message(1000, 0xAA);

    constexpr int iterations = 1000;

    auto start = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < iterations; ++i) {
        auto sig = sign(pk, sk, makeSlice(message));
    }

    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

    std::cout << "Average signing time: "
              << (duration.count() / static_cast<double>(iterations))
              << " μs\n";
}
```

#### Compare Algorithms

```
void compareAlgorithms()
{
    std::cout << "=== Signing Performance ===\n";

    // Ed25519
    {
        auto [pk, sk] = randomKeyPair(KeyType::ed25519);
        auto time = measureSign(pk, sk, 1000);
        std::cout << "Ed25519:   " << time << " μs/op\n";
    }

    // secp256k1
    {
        auto [pk, sk] = randomKeyPair(KeyType::secp256k1);
        auto time = measureSign(pk, sk, 1000);
        std::cout << "secp256k1: " << time << " μs/op\n";
    }
}
```

### Inspecting Key Material

#### View Public Key Details

```
void inspectPublicKey(PublicKey const& pk)
{
    std::cout << "=== Public Key Analysis ===\n";

    auto type = publicKeyType(pk);
    std::cout << "Type: ";
    if (!type) {
        std::cout << "INVALID\n";
        return;
    }

    if (*type == KeyType::secp256k1)
        std::cout << "secp256k1 (ECDSA)\n";
    else if (*type == KeyType::ed25519)
        std::cout << "ed25519 (EdDSA)\n";

    std::cout << "Size: " << pk.size() << " bytes\n";
    std::cout << "Hex: " << strHex(pk) << "\n";

    auto accountID = calcAccountID(pk);
    std::cout << "Account ID (hex): " << strHex(accountID) << "\n";
    std::cout << "Address: " << toBase58(accountID) << "\n";
}
```

#### Verify Key Pair Consistency

```
bool verifyKeyPair(PublicKey const& pk, SecretKey const& sk)
{
    // Derive public key from secret
    auto derived = derivePublicKey(publicKeyType(pk).value(), sk);

    if (derived != pk) {
        std::cout << "ERROR: Public key doesn't match secret key!\n";
        std::cout << "Expected: " << strHex(pk) << "\n";
        std::cout << "Derived:  " << strHex(derived) << "\n";
        return false;
    }

    std::cout << "✓ Key pair is consistent\n";
    return true;
}
```

### Testing Signature Canonicality

#### Check secp256k1 Canonicality

```
void testCanonicality(Slice const& signature)
{
    auto canon = ecdsaCanonicality(signature);

    if (!canon) {
        std::cout << "ERROR: Invalid signature format\n";
        return;
    }

    switch (*canon) {
        case ECDSACanonicality::fullyCanonical:
            std::cout << "✓ Fully canonical (S ≤ order/2)\n";
            break;
        case ECDSACanonicality::canonical:
            std::cout << "⚠ Canonical but not fully (S > order/2)\n";
            std::cout << "  Should normalize for malleability prevention\n";
            break;
    }
}
```

### Hex Dump Utility

```
void hexDump(void const* data, size_t size, std::string const& label = "")
{
    if (!label.empty())
        std::cout << label << ":\n";

    auto const* bytes = static_cast<uint8_t const*>(data);

    for (size_t i = 0; i < size; ++i) {
        if (i % 16 == 0)
            std::cout << std::hex << std::setw(4) << std::setfill('0') << i << ": ";

        std::cout << std::hex << std::setw(2) << std::setfill('0')
                  << static_cast<int>(bytes[i]) << " ";

        if ((i + 1) % 16 == 0 || i + 1 == size)
            std::cout << "\n";
    }

    std::cout << std::dec;  // Reset to decimal
}

// Usage:
hexDump(signature.data(), signature.size(), "Signature");
```

### Address Sanitizer

#### Compile with AddressSanitizer

```
# Build with ASan
cmake -DCMAKE_BUILD_TYPE=Debug \
      -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
      ..
make

# Run
./rippled --standalone
```

#### Detect Issues

* Use-after-free
* Heap buffer overflow
* Stack buffer overflow
* Memory leaks
* Use of uninitialized memory

### Common Debug Scenarios

#### Debug Signature Verification Failure

```
void debugVerificationFailure(
    PublicKey const& pk,
    Slice const& message,
    Slice const& signature)
{
    std::cout << "=== Debugging Signature Verification ===\n";

    // Check public key
    auto pkType = publicKeyType(pk);
    if (!pkType) {
        std::cout << "ERROR: Invalid public key format\n";
        return;
    }
    std::cout << "✓ Public key type: "
              << (*pkType == KeyType::ed25519 ? "ed25519" : "secp256k1")
              << "\n";

    // Check signature size
    if (*pkType == KeyType::ed25519 && signature.size() != 64) {
        std::cout << "ERROR: Ed25519 signature should be 64 bytes, got "
                  << signature.size() << "\n";
        return;
    }
    std::cout << "✓ Signature size: " << signature.size() << " bytes\n";

    // Check canonicality
    if (*pkType == KeyType::secp256k1) {
        auto canon = ecdsaCanonicality(signature);
        if (!canon) {
            std::cout << "ERROR: Invalid DER encoding\n";
            return;
        }
        if (*canon != ECDSACanonicality::fullyCanonical) {
            std::cout << "WARNING: Signature not fully canonical\n";
        }
    }

    // Try verification
    bool valid = verify(pk, message, signature, true);
    std::cout << "Verification result: " << (valid ? "✓ VALID" : "✗ INVALID") << "\n";

    if (!valid) {
        std::cout << "\nPossible causes:\n";
        std::cout << "- Wrong public key\n";
        std::cout << "- Wrong message\n";
        std::cout << "- Corrupted signature\n";
        std::cout << "- Algorithm mismatch\n";
    }
}
```

### Summary

Essential debugging tools and techniques:

1. **Logging**: Enable trace logging for crypto operations
2. **Standalone mode**: Test without network complexity
3. **GDB**: Step through code, inspect variables
4. **Valgrind**: Detect memory issues
5. **Unit tests**: Verify correctness
6. **Benchmarking**: Measure performance
7. **Inspection tools**: Examine keys, signatures, addresses
8. **Sanitizers**: Catch memory errors automatically

**Best practices:**

* Test with both ed25519 and secp256k1
* Verify canonicality for secp256k1
* Check key pair consistency
* Use hex dumps for visual inspection
* Always check error returns


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.xrpl-commons.org/core-dev-bootcamp/module04/appendices/debugging-and-development-tools.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
