---
title: "Litecoin"
description: "Bitcoin's driver with Litecoin's prefixes. Five address formats on mainnet and testnet and its own signed message preamble."
canonical_url: "https://keys.agntn.dev/blockchains/litecoin"
---
# Litecoin

> Bitcoin's driver with Litecoin's prefixes. Five address formats on mainnet and testnet and its own signed message preamble.

<chain-facts coin="2" curve="secp256k1" driver="litecoin" formats="legacy, p2sh, segwit, p2wsh, taproot">



</chain-facts>

## Load it

```js
import { useBlockchain, blockchains } from "@agntn/keys";

const litecoinChain = useBlockchain(await blockchains.litecoin()());
const testnetChain = useBlockchain(await blockchains.litecoin({ network: "testnet" })());
```

Anything other than `mainnet` and `testnet` throws in the constructor. There's no signet or regtest table.

## Same five formats, different prefixes

<table>
<thead>
  <tr>
    <th>
      Type
    </th>
    
    <th>
      Mainnet
    </th>
    
    <th>
      Testnet
    </th>
    
    <th>
      Encoding
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        legacy
      </code>
      
       (default)
    </td>
    
    <td>
      <code>
        L...
      </code>
    </td>
    
    <td>
      <code>
        m...
      </code>
      
       or <code>
        n...
      </code>
    </td>
    
    <td>
      base58check, version <code>
        0x30
      </code>
      
       / <code>
        0x6f
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        p2sh
      </code>
    </td>
    
    <td>
      <code>
        M...
      </code>
    </td>
    
    <td>
      <code>
        Q...
      </code>
    </td>
    
    <td>
      base58check, version <code>
        0x32
      </code>
      
       / <code>
        0x3a
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        segwit
      </code>
    </td>
    
    <td>
      <code>
        ltc1q...
      </code>
    </td>
    
    <td>
      <code>
        tltc1q...
      </code>
    </td>
    
    <td>
      bech32, witness v0, P2WPKH
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        p2wsh
      </code>
    </td>
    
    <td>
      <code>
        ltc1q...
      </code>
    </td>
    
    <td>
      <code>
        tltc1q...
      </code>
    </td>
    
    <td>
      bech32, witness v0, script hash
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        taproot
      </code>
    </td>
    
    <td>
      <code>
        ltc1p...
      </code>
    </td>
    
    <td>
      <code>
        tltc1p...
      </code>
    </td>
    
    <td>
      bech32m, witness v1
    </td>
  </tr>
</tbody>
</table>

```js
const privateKey = "0000000000000000000000000000000000000000000000000000000000000001";
const publicKey = litecoinChain.getKeyPublic(privateKey);

litecoinChain.getAddress(publicKey); // LVuDpNCSSj6pQ7t9Pv6d6sUkLKoqDEVUnJ
litecoinChain.getAddress(publicKey, "p2sh"); // MR8UQSBr5ULwWheBHznrHk2jxyxkHQu8vB
litecoinChain.getAddress(publicKey, "segwit"); // ltc1qw508d6qejxtdg4y5r3zarvary0c5xw7kgmn4n9
litecoinChain.getAddress(publicKey, "taproot"); // ltc1pmfr3p9j00pfxjh0zmgp99y8zftmd3s5pmedqhyptwy6lm87hf5sszjagvq
```

The hashing is Bitcoin's, `RIPEMD160(SHA256(pubkey))`, the same taproot tweak too. Only the version bytes and the bech32 prefix change, which is why the segwit address above is `bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4` on Bitcoin with a different tail: same 20 bytes, different human readable part, different checksum.

Testnet legacy addresses start with `m` or `n`, exactly like Bitcoin testnet, and the WIF prefix is shared as well. A Litecoin testnet key and a Bitcoin testnet key are the same string. Not a bug, that's how Litecoin Core did it.

MWEB isn't supported, neither addresses nor anything else.

## Validation

```js
litecoinChain.validateAddress("LVuDpNCSSj6pQ7t9Pv6d6sUkLKoqDEVUnJ"); // true
litecoinChain.validateAddress("MR8UQSBr5ULwWheBHznrHk2jxyxkHQu8vB"); // true
litecoinChain.validateAddress("ltc1qw508d6qejxtdg4y5r3zarvary0c5xw7kgmn4n9"); // true
litecoinChain.validateAddress("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"); // false, wrong network
```

One extra: the old P2SH prefix, `3...` on mainnet and `2...` on testnet, still validates. Old wallets still produce it, so rejecting it would only break real users. `getAddress` never emits it, you always get `M`.

## Mnemonics

`deriveHDWallet` reads the purpose the way Bitcoin does, with coin type 2:

```js
litecoinChain.deriveHDWallet(mnemonic, { path: "m/84'/2'/0'/0/0" }).address; // ltc1q..., segwit from purpose 84
litecoinChain.deriveHDWallet(mnemonic, { path: "m/44'/2'/0'/0/0" }).address; // L..., legacy from purpose 44
```

## WIF

```js
import { encode } from "@agntn/keys/wif";

encode(privateKey, { chain: "litecoin" }); // T33ydQRKp4FCW5LCLLUB7deioUMoveiwekdwUwyfRDeGZm76aUjV
```

Version `0xb0` on mainnet, so compressed keys start with `T` and uncompressed ones with `6`. Testnet is `0xef`, the Bitcoin one.

## Signing

Same construction as Bitcoin with `"\x19Litecoin Signed Message:\n"` in front: double SHA-256, secp256k1, 64 bytes of `r||s` in hex. A Bitcoin signature over the same key and message is a different string because the preamble differs, so verify with the chain that signed. `{ recovered: true }` gives Litecoin Core's base64, byte for byte its `signmessagewithprivkey` vector.

## Where it lives

`src/blockchains/litecoin.ts` is the network table, the preamble and the validation extra. Everything else, signing included, comes from `AbstractBitcoinBlockchain` in `src/utils/bitcoin.ts`, shared with Bitcoin and Bitcoin Gold.


## Sitemap

See the full [sitemap](https://keys.agntn.dev/sitemap.md) for all pages.
