How to use checksum to validate ADA address?

I have not been able to find a technical explanation of how to validate that a given string is a valid Cardano address via its checksum. The closest that I could find in the documentation is here. However, none of the values in the example are ADA addresses. Given an address such as DdzFFzCqrhsgwQmeWNBTsG8VjYunBLK9GNR93GSLTGj1FeMm8kFoby2cTHxEHBEraHQXmgTtFGz7fThjDRNNvwzcaw6fQdkYySBneRas, how do I get it into the format where it can be validated via CRC32? I assume I decode it from base58, but then what?

1 Like

You could back into it, check how the API is returning interesting information about an address.

3 Likes

Just a heads up: Cardano (currently) has 2 different addressing schemes.

3 Likes

Yep, Yoroi and Daedalus wallets use different key schemes.

1 Like

If you are using Rust check out the cardano_address_is_valid() function - an example I just did, calling Rust from C, your address is the first one.

smith$ cat check_address.c 

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#include <string.h>

#include "../cardano.h"

int main(int argc, char* argv[]) {

char *a="DdzFFzCqrhsgwQmeWNBTsG8VjYunBLK9GNR93GSLTGj1FeMm8kFoby2cTHxEHBEraHQXmgTtFGz7fThjDRNNvwzcaw6fQdkYySBneRas";

printf("address:\n%s\n? is valid: %s\n",a, cardano_address_is_valid(a) ? "NO" : "YES");

char *b="DdzFFzCqrhsgwQmeWNBTsG8VjYunBLK9GNR93GSLTGj1FeMm8kFoby2cTHxEHBEraHQXmgTtFGz7fThjDRNNvwzcaw6fQdkYySBneRaX";

printf("address:\n%s\n? is valid: %s\n",b, cardano_address_is_valid(b) ? "NO" : "YES");

return 0;

}

smith$ ./a.out

address:

DdzFFzCqrhsgwQmeWNBTsG8VjYunBLK9GNR93GSLTGj1FeMm8kFoby2cTHxEHBEraHQXmgTtFGz7fThjDRNNvwzcaw6fQdkYySBneRas

? is valid: YES

address:

DdzFFzCqrhsgwQmeWNBTsG8VjYunBLK9GNR93GSLTGj1FeMm8kFoby2cTHxEHBEraHQXmgTtFGz7fThjDRNNvwzcaw6fQdkYySBneRaX

? is valid: NO
4 Likes

Hijack threads much?

1 Like

I’m also really interested in creating a Cardano address validator. Would prefer a javascript solution though.

I made an address checker in python:

import base58
import cbor
import binascii
import sys

addr = sys.argv[1]

decodedAddr = base58.b58decode(addr)
decodedAddr = cbor.loads(decodedAddr)
taggedAddr = decodedAddr[0]
addrChecksum = decodedAddr[1]
Checksum = binascii.crc32(taggedAddr.value)

print("Address data: ", taggedAddr.value.hex())
print("Provided Checksum:", addrChecksum)
print("Computed Checksum:", Checksum)
print("Match: ", addrChecksum == Checksum)

Edit: I put it on github

3 Likes

I am getting this error when I run the script:

addr = sys.argv[1]
IndexError: list index out of range

You need to specify the address to check in the command line, like so:

python addrCheck.py DdzFFzCqrhsgwQmeWNBTsG8VjYunBLK9GNR93GSLTGj1FeMm8kFoby2cTHxEHBEraHQXmgTtFGz7fThjDRNNvwzcaw6fQdkYySBneRas
1 Like

Very good.

Did you provide an argument, like this:

$: python ./b58.py DdzFFzCqrhszg6GVew17iad3FDTTpAKo91pwhj7Nc64v1myy3NwGoPZ4YmTbqyuxQQMDPAA9FSbYniWHWS24jK6bvKb7YkbgRbjhZ3Qb

('Address data: ', '83581c9fb50d50654faedb0ee769fe184cffb4d206f4e966c0b2d95604828ca101581e581c50ec25b2d5c9eb7eb30c93bfafe85343c5b4158e1304d9db81fd38c800')

('Provided Checksum:', 443419360L)

('Computed Checksum:', 443419360)

('Match: ', True)
2 Likes

Thanks. In hindsight that was not a very smart question.

1 Like

Lol all good :stuck_out_tongue:
I made a new version on github that will catch that error.

JS Implementation of @Steve python validator

const base58 = require('./crypto/base58')
const cbor = require('cbor')
const crc32 = require('crc-32')

function isValidAdaAddress (address, currency, networkType) {
  var decodedAddr = base58.decode(address)
  decodedAddr = cbor.decode(Buffer.from(decodedAddr))
  var taggedAddr = decodedAddr[0]
  if (taggedAddr === undefined) {
    return false
  }
  var addrChecksum = decodedAddr[1]
  var calculatedChecksum = crc32.buf(taggedAddr.value)
  console.log('DECODED ADDRESS', taggedAddr.value.toString('hex'))
  console.log('CALCULATED CHECKSUM', calculatedChecksum)
  console.log('CHECKSUM:', addrChecksum)
  return calculatedChecksum === addrChecksum
}

module.exports = {
  isValidAddress: function (address, currency, networkType) {
    return isValidAdaAddress(address, currency, networkType)
  }
}

Base58 Implemented Locally

var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
var ALPHABET_MAP = {}
for (var i = 0; i < ALPHABET.length; ++i) {
  ALPHABET_MAP[ALPHABET.charAt(i)] = i
}
var BASE = ALPHABET.length

module.exports = {
  decode: function (string) {
    if (string.length === 0) return []

    var i; var j; var bytes = [0]
    for (i = 0; i < string.length; ++i) {
      var c = string[i]
      if (!(c in ALPHABET_MAP)) throw new Error('Non-base58 character')

      for (j = 0; j < bytes.length; ++j) bytes[j] *= BASE
      bytes[0] += ALPHABET_MAP[c]

      var carry = 0
      for (j = 0; j < bytes.length; ++j) {
        bytes[j] += carry
        carry = bytes[j] >> 8
        bytes[j] &= 0xff
      }

      while (carry) {
        bytes.push(carry & 0xff)
        carry >>= 8
      }
    }
    // deal with leading zeros
    for (i = 0; string[i] === '1' && i < string.length - 1; ++i) {
      bytes.push(0)
    }

    return bytes.reverse()
  }
}
1 Like

Thanks looks good.

Very similar to: