johguse / profanity

Vanity address generator for Ethereum
834 stars 324 forks source link

Option for scoring based on # of zero-bytes in address #57

Closed mindnumbe closed 2 years ago

mindnumbe commented 2 years ago

This tool is fantastic for finding gas efficient ethereum addresses and I typically use it with the form of .\profanity --leading 0 for this purpose.

This outputs addresses like: 0x0000... 0x00000.. 0x000000000... All of which save significant amounts of gas through long term use. However, gas efficiency on eth addresses is also driven through zero-bytes, not just leading zeros.

It'd be incredible if there were a scoring mechanism based on this premise of finding zero-bytes anywhere throughout the address, rather than just the beginning.

For example Score | Address 4 | 0x00000000..... 5 | 0x000000004124001232..... 6 | 0x00000041002400120032..... 9 | 0x00000000410024001200320000...

As I run through the .\profanity --leading 0 program, I wonder how many addresses with more zero-bytes are skipped over.

For more reading on this: https://medium.com/coinmonks/on-efficient-ethereum-addresses-3fef0596e263

johguse commented 2 years ago

I don't maintain this project any longer but I haven't ruled out resuming it in the future, it's a long story. For this particular case you should be able to patch it yourself as it only requires changes to the OpenCL code.

Open profanity.cl in editor of choice and change the function profanity_score_leading to:

__kernel void profanity_score_leading(__global mp_number * const pInverse, __global result * const pResult, __constant const uchar * const data1, __constant const uchar * const data2, const uchar scoreMax) {
    const size_t id = get_global_id(0);
    __global const uchar * const hash = pInverse[id].d;
    int score = 0;

    for (int i = 0; i < 20; ++i) {
        score += (hash[i] == 0);
    }

    profanity_result_update(id, hash, pResult, score, scoreMax);
}

I haven't tested it but I think that should do it.

mindnumbe commented 2 years ago

I don't maintain this project any longer but I haven't ruled out resuming it in the future, it's a long story. For this particular case you should be able to patch it yourself as it only requires changes to the OpenCL code.

Open profanity.cl in editor of choice and change the function profanity_score_leading to:

__kernel void profanity_score_leading(__global mp_number * const pInverse, __global result * const pResult, __constant const uchar * const data1, __constant const uchar * const data2, const uchar scoreMax) {
  const size_t id = get_global_id(0);
  __global const uchar * const hash = pInverse[id].d;
  int score = 0;

  for (int i = 0; i < 20; ++i) {
      score += (hash[i] == 0);
  }

  profanity_result_update(id, hash, pResult, score, scoreMax);
}

I haven't tested it but I think that should do it.

This works flawlessly! Thank you very much! Now that you've helped and pointed me in the direction on how to adjust the scoring mechanism, I've rewritten this to adjust scoring to maximize gas efficiency.

From the article I linked in the OP:

When it comes to addresses in particular, we can pull off some nice gas savings as follows: if the address has at least four leading zero bytes (or eight leading zeroes in hex-encoded format), then each address will only need to take up 16 bytes.

The goal is to find 4 leading zero-bytes with bonus points for any additionals.

__kernel void profanity_score_leading(__global mp_number * const pInverse, __global result * const pResult, __constant const uchar * const data1, __constant const uchar * const data2, const uchar scoreMax) {
    const size_t id = get_global_id(0);
    __global const uchar * const hash = pInverse[id].d;
    int score = 0;

    if (((hash[0] == 0) + (hash[1] == 0) + (hash[2] == 0) + (hash[3] == 0)) == 4) {
        score = 4;            
        for (int i = 4; i < 20; ++i) {
            score += (hash[i] == 0);
        }
    }

    profanity_result_update(id, hash, pResult, score, scoreMax);
}

I've never written C or .cl before so I don't know if this is optimized, but it appears to be working.

Score | Address 4 | 0x000000001234... 5 | 0x00000000123400...

This is amazing! I found a 5 zero-byte address in just 80 seconds, where typically it would take my rig ~5 hrs to find it with leading zeros only.

johguse commented 2 years ago

That's great!

The hash is represented as 4 32-bit integers and checking individual bytes of these is necessary in some scoring scenarios but in this case four leading zeros is the same as the first 32-bit integer being zero, so that could increase speeds slightly.

__kernel void profanity_score_leading(__global mp_number * const pInverse, __global result * const pResult, __constant const uchar * const data1, __constant const uchar * const data2, const uchar scoreMax) {
  const size_t id = get_global_id(0);
  __global const uchar * const hash = pInverse[id].d;
  int score = 0;

    if (pInverse[id].d[0] == 0) {
        score = 4;            
        for (int i = 4; i < 20; ++i) {
          score += (hash[i] == 0);
      }
    }

  profanity_result_update(id, hash, pResult, score, scoreMax);
}
johguse commented 2 years ago

And as said, I've not maintained this project for a long time and if you're in need for more speed there's other solutions out there that are faster.

I know of at least one optimization for this project that could roughly double the speed which I missed the first time around (reflection of coordinates against the X-axis on the elliptical curve). I wrote a CUDA version which allowed for heavier optimizations that has massive speed gains on nVidia platforms which I never got around to releasing. While researching optimizations for it I found a project (can't recall the name) which had support for Ethereum vanity addressees that was just slightly faster than the CUDA version I'd put together.

Since that project already existed and was faster and I thought there wasn't room for more improvement I abandoned the CUDA version I was working on (and this OpenCL version with it).

So there's something faster out there if you need it, just so you know!

mindnumbe commented 2 years ago

Your optimization with using if (pInverse[id].d[0] == 0) is working great!

I appreciate you taking the time to help me on a project you no longer maintain, and also letting me know there are other faster options. The thing with vanity ethereum addresses is the difficulty for each additional zero-byte scales with 16^2 more difficulty, and even a doubling in speed leaves higher values far out of reach. Far more important to me is flexible scoring patterns in a language I can adjust, and the work you've written here is perfect for that.

Now with 5 and 6 zero-byte addresses in easy reach I am very happy and much better off! Great work man

definevalue commented 2 years ago

kernel void profanity_score_leading(global mp_number const pInverse, __global result const pResult, constant const uchar * const data1, constant const uchar const data2, const uchar scoreMax) { const size_t id = get_global_id(0); __global const uchar const hash = pInverse[id].d; int score = 0;

if (pInverse[id].d[0] == 0) {
    score = 4;            
    for (int i = 4; i < 20; ++i) {
      score += (hash[i] == 0);
  }
}

profanity_result_update(id, hash, pResult, score, scoreMax); }

And as said, I've not maintained this project for a long time and if you're in need for more speed there's other solutions out there that are faster.

I know of at least one optimization for this project that could roughly double the speed which I missed the first time around (reflection of coordinates against the X-axis on the elliptical curve). I wrote a CUDA version which allowed for heavier optimizations that has massive speed gains on nVidia platforms which I never got around to releasing. While researching optimizations for it I found a project (can't recall the name) which had support for Ethereum vanity addressees that was just slightly faster than the CUDA version I'd put together.

Since that project already existed and was faster and I thought there wasn't room for more improvement I abandoned the CUDA version I was working on (and this OpenCL version with it).

So there's something faster out there if you need it, just so you know!

What is this other project because i've only ever seen this with GPU's for Ethereum if you dont mind me asking

straightnun commented 2 years ago

@mindnumbe You say, the optimization was succesful - are you building on Windows, or Linux? Ive tried building the program (even without changing code), but cant get profanity,x64 to detect my GPU, while the "default program" (profanity.exe) is running perfect.