Skip to content

Instantly share code, notes, and snippets.

@intelliot
Last active August 16, 2022 23:34
Show Gist options
  • Save intelliot/f15188d3780edcd09618c1e618254d82 to your computer and use it in GitHub Desktop.
Save intelliot/f15188d3780edcd09618c1e618254d82 to your computer and use it in GitHub Desktop.

Where is the code in rippled to generate an NFT ID (NFTokenID) from a mint txn?

With XLS-20, the NFTokenID is generated from a mint transaction here:

uint256
NFTokenMint::createNFTokenID(
    std::uint16_t flags,
    std::uint16_t fee,
    AccountID const& issuer,
    nft::Taxon taxon,
    std::uint32_t tokenSeq)
{
    // An issuer may issue several NFTs with the same taxon; to ensure that NFTs
    // are spread across multiple pages we lightly mix the taxon up by using the
    // sequence (which is not under the issuer's direct control) as the seed for
    // a simple linear congruential generator.  cipheredTaxon() does this work.
    taxon = nft::cipheredTaxon(tokenSeq, taxon);

    // The values are packed inside a 32-byte buffer, so we need to make sure
    // that the endianess is fixed.
    flags = boost::endian::native_to_big(flags);
    fee = boost::endian::native_to_big(fee);
    taxon = nft::toTaxon(boost::endian::native_to_big(nft::toUInt32(taxon)));
    tokenSeq = boost::endian::native_to_big(tokenSeq);

    std::array<std::uint8_t, 32> buf{};

    auto ptr = buf.data();

    // This code is awkward but the idea is to pack these values into a single
    // 256-bit value that uniquely identifies this NFT.
    std::memcpy(ptr, &flags, sizeof(flags));
    ptr += sizeof(flags);

    std::memcpy(ptr, &fee, sizeof(fee));
    ptr += sizeof(fee);

    std::memcpy(ptr, issuer.data(), issuer.size());
    ptr += issuer.size();

    std::memcpy(ptr, &taxon, sizeof(taxon));
    ptr += sizeof(taxon);

    std::memcpy(ptr, &tokenSeq, sizeof(tokenSeq));
    ptr += sizeof(tokenSeq);
    assert(std::distance(buf.data(), ptr) == buf.size());

    return uint256::fromVoid(buf.data());
}

With secp256k1 public keys, the first byte can be 0x02 or 0x03. Why?

These public keys were used in the Bitcoin protocol. You can learn more about public keys here. Specific to the XRP Ledger, step 2 on this page summarizes it:

Convert the root public key to its 33-byte compressed form.

The uncompressed form of any ECDSA public key consists of a pair of 32-byte integers: an X coordinate, and a Y coordinate. The compressed form is the X coordinate and a one-byte prefix: 0x02 if the Y coordinate is even, or 0x03 if the Y coordinate is odd.

You can convert an uncompressed public key to the compressed form with the openssl commandline tool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment