ARDOR address generation

Hello! How to generate ARDOR address and public key and private key in C++?

1 Like

Generates a passphrase using the words from the BIP39 word list.

It could be something like:

#include <iostream>
#include <string>
#include <random>
#include <algorithm>
#include <vector>

std::string generatePassphrase() {
    std::string passPhrase = "";

    std::vector<std::string> words = {
        "apple", "banana", "cherry", "date", "elderberry",
        "fig", "grape", "honeydew", "imbe", "jujube",
        "kiwi", "lemon", "mango", "nectarine", "orange",
        "papaya", "quince", "raspberry", "strawberry", "tangerine"
    };

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, words.size()-1);

    int bits = 128;
    int n = words.size();

    std::vector<int> random(bits / 32);
    for (int i = 0; i < random.size(); i++) {
        random[i] = gen();
    }

    std::vector<std::string> phraseWords;
    int x, w1, w2, w3;

    for (int i = 0; i < random.size(); i++) {
        x = random[i];
        w1 = x % n;
        w2 = (((x / n) >> 0) + w1) % n;
        w3 = (((((x / n) >> 0) / n) >> 0) + w2) % n;

        phraseWords.push_back(words[w1]);
        phraseWords.push_back(words[w2]);
        phraseWords.push_back(words[w3]);
    }

    passPhrase = std::accumulate(std::begin(phraseWords), std::end(phraseWords), passPhrase);

    for (int i = 0; i < random.size(); i++) {
        random[i] = gen();
    }

    return passPhrase;
}

int main() {
    std::cout << generatePassphrase() << std::endl;
    return 0;
}

The C++ random library has been used to generate random numbers. The list of words used in the function has also been defined in the function itself. Use the original from Github.

The code is not tested, it is only a small indication of how you might proceed.

1 Like

Thank you! I want to learn how to make an ARDOR address from a passphrase.

1 Like

What ArdorJS (the library I update for ReactJS) does is the following:

function secretPhraseToAccountId(secretPhrase, numeric) {
  var pubKey = secretPhraseToPublicKey(secretPhrase);
  return publicKeyToAccountId(pubKey, numeric);
}
function publicKeyToAccountId(publicKey, numeric) {
  var arr = helpers.hexStringToByteArray(publicKey);
  var account = helpers.simpleHash(arr, "hex");

  var slice = helpers.hexStringToByteArray(account).slice(0, 8);
  var accountId = helpers.byteArrayToBigInteger(slice).toString();

  if (numeric) {
    return accountId;
  }
  var address = new NxtAddress();
  if (!address.set(accountId)) {
    return "";
  }
  return address.toString();
}

Helpers:

function hexStringToByteArray(str) {
  var bytes = [];
  var i = 0;
  if (0 !== str.length % 2) {
    bytes.push(charToNibble[str[0]]);
    ++i;
  }

  for (; i < str.length - 1; i += 2) {
    bytes.push((charToNibble[str[i]] << 4) + charToNibble[str[i + 1]]);
  }

  return bytes;
}
function simpleHash(message, encoding) {
  if (message instanceof Array) {
    message = Buffer.from(message);
    message = cryptoJs.lib.WordArray.create(message);
  }

  const sig = cryptoJs.SHA256(message);
  if (encoding != "hex") {
    return Buffer.from(sig.toString(hex), "hex");
  } else {
    return sig.toString(hex);
  }
}

See: GitHub - mrv777/ardorjs: Transaction signing for ardor transactions, and ardor address creations

1 Like

Unfortunately I don't think there is a convenient implementation of the Ardor public/private key cryptography in C++. Or at least I'm not aware of such. The cryptography we use is based on this work Curve25519: high-speed elliptic-curve cryptography. Our code is ported from the 64-bit implementation according to a comment in our code. So probably you could use that C library directly.

To get a private key from a secret phrase, you need to port this piece of code to C++

public static byte[] getPrivateKey(String secretPhrase) {
    if (secretPhrase == null) {
        return null;
    }
    byte[] s = Crypto.sha256().digest(Convert.toBytes(secretPhrase));
    Curve25519.clamp(s);
    return s;
}

So you need to store the secret into a byte array with UTF-8 encoding, then you also need to generate a SHA-256 from that byte array.

Having the private key, you should (hopefully) be able to generate a public key using that library. Then having the public key, to get a numberic account ID, you should port this piece of code

public static long getId(byte[] publicKey) {
    byte[] publicKeyHash = Crypto.sha256().digest(publicKey);
    return Convert.fullHashToId(publicKeyHash);
}

So, again SHA-256 and then fullHashToId returns the first 64 bits of the hash.

Having the account ID in numeric format, to display it in Reed-Solomon format, you need a Reed-Solomon implementation. But that shouldn't be hard to find.

3 Likes