Post
Topic
Board Development & Technical Discussion
Re: "Fixing 24-Word Mnemonic Support in bip39-solver-gpu"
by
ThewsyRum
on 12/12/2024, 19:39:08 UTC

I read what mcdouglasx said and took it as a challenge for myself. Take a good look at what I did: The ipad_key and opad_key arrays with 128 bytes each to perform HMAC operations. When the mnemonic_length exceeds 128 bytes (24 words), the remainder of the key is not being processed correctly. Therefore, it would be necessary to implement a key normalization process that complies with HMAC. If the key is larger than the block size (128 bytes for SHA-512), it must first be hashed to reduce its size. Then, it should be padded with zeros to reach 128 bytes if needed.

The changes I made to the file int_to_address.cl look like this:
Code:
__kernel void int_to_address(ulong mnemonic_start_hi, ulong mnemonic_start_lo, __global uchar * target_mnemonic, __global uchar * found_mnemonic) {
    ulong idx = get_global_id(0);

    ulong mnemonic_lo = mnemonic_start_lo + idx;
    ulong mnemonic_hi = mnemonic_start_hi;

    // ... [existing code to construct 'bytes' and 'mnemonic']

    // Constructing the mnemonic
    uchar mnemonic[180] = {0};
    uchar mnemonic_length = 11;
    for(int i = 0; i < 12; i++) {
        int word_index = indices[i];
        int word_length = word_lengths[word_index];
        mnemonic_length += word_lengths[word_index];
    }

    int mnemonic_index = 0;
    for (int i = 0; i < 12; i++) {
        int word_index = indices[i];
        int word_length = word_lengths[word_index];
       
        for(int j = 0; j < word_length; j++) {
            mnemonic[mnemonic_index] = words[word_index][j];
            mnemonic_index++;
        }
        mnemonic[mnemonic_index] = 32; // Space
        mnemonic_index++;
    }
    mnemonic[mnemonic_index - 1] = 0; // Null termination

    // Key Normalization
    uchar normalized_key[128] = {0};
    if (mnemonic_length > 128) {
        // If the mnemonic is larger than 128 bytes, hash it with SHA-512
        sha512(&mnemonic, mnemonic_length, &normalized_key);
        // Remaining bytes are already zero-padded (done at initialization)
    } else {
        // If the mnemonic is less than or equal to 128 bytes, copy it directly
        for(int i = 0; i < mnemonic_length; i++) {
            normalized_key[i] = mnemonic[i];
        }
        // Remaining bytes are already zero-padded
    }

    // Initialization of ipad_key and opad_key
    uchar ipad_key[128];
    uchar opad_key[128];
    for(int x = 0; x < 128; x++) {
        ipad_key[x] = 0x36;
        opad_key[x] = 0x5c;
    }

    // Apply XOR with the normalized key
    for(int x = 0; x < 128; x++) {
        ipad_key[x] ^= normalized_key[x];
        opad_key[x] ^= normalized_key[x];
    }

    // Continue seed derivation process
    uchar seed[64] = {0};
    uchar sha512_result[64] = {0};
    uchar key_previous_concat[256] = {0};
    uchar salt[12] = {109, 110, 101, 109, 111, 110, 105, 99, 0, 0, 0, 1};
    for(int x = 0; x < 128; x++) {
        key_previous_concat[x] = ipad_key[x];
    }
    for(int x = 0; x < 12; x++) {
        key_previous_concat[x + 128] = salt[x];
    }

    sha512(&key_previous_concat, 140, &sha512_result);
    copy_pad_previous(&opad_key, &sha512_result, &key_previous_concat);
    sha512(&key_previous_concat, 192, &sha512_result);
    xor_seed_with_round(&seed, &sha512_result);

    for(int x = 1; x < 2048; x++) {
        copy_pad_previous(&ipad_key, &sha512_result, &key_previous_concat);
        sha512(&key_previous_concat, 192, &sha512_result);
        copy_pad_previous(&opad_key, &sha512_result, &key_previous_concat);
        sha512(&key_previous_concat, 192, &sha512_result);
        xor_seed_with_round(&seed, &sha512_result);
    }

    // ... [existing code for key generation and address verification]

    if(found_target == 1) {
        found_mnemonic[0] = 0x01;
        for(int i = 0; i < mnemonic_index; i++) {
            target_mnemonic[i] = mnemonic[i];
        }
    }
}

And in the file just_seed.cl, it turned out like this:
Code:
__kernel void just_seed(ulong mnemonic_start_hi, ulong mnemonic_start_lo, __global uchar * target_mnemonic, __global uchar * found_mnemonic) {
    ulong idx = get_global_id(0);

    ulong seed_start = idx * 64;
    ulong mnemonic_lo = mnemonic_start_lo + idx;
    ulong mnemonic_hi = mnemonic_start_hi;

    // ... [existing code to build 'bytes' and 'mnemonic']

    // Mnemonic construction
    uchar mnemonic[180];
    int mnemonic_index = 0;
    for (int i = 0; i < 12; i++) {
        int word_index = indices[i];
        int word_length = word_lengths[word_index];
       
        for(int j = 0; j < word_length; j++) {
            mnemonic[mnemonic_index] = words[word_index][j];
            mnemonic_index++;
        }
        mnemonic[mnemonic_index] = 32; // Space
        mnemonic_index++;
    }
    mnemonic[mnemonic_index - 1] = 0; // Null termination

    uchar mnemonic_length = 11 + word_lengths[indices[0]] + word_lengths[indices[1]] + word_lengths[indices[2]] + word_lengths[indices[3]] + word_lengths[indices[4]] + word_lengths[indices[5]] + word_lengths[indices[6]] + word_lengths[indices[7]] + word_lengths[indices[8]] + word_lengths[indices[9]] + word_lengths[indices[10]] + word_lengths[indices[11]];

    // Key normalization
    uchar normalized_key[128] = {0};
    if (mnemonic_length > 128) {
        // If the mnemonic is larger than 128 bytes, hash with SHA-512
        sha512(&mnemonic, mnemonic_length, &normalized_key);
        // Fill remaining bytes with zeros (already done during initialization)
    } else {
        // If the mnemonic is 128 bytes or less, copy directly
        for(int i = 0; i < mnemonic_length; i++) {
            normalized_key[i] = mnemonic[i];
        }
        // Remaining bytes are already filled with zeros
    }

    // Initialization of ipad_key and opad_key
    uchar ipad_key[128];
    uchar opad_key[128];
    for(int x = 0; x < 128; x++) {
        ipad_key[x] = 0x36;
        opad_key[x] = 0x5c;
    }

    // Apply XOR with normalized key
    for(int x = 0; x < 128; x++) {
        ipad_key[x] ^= normalized_key[x];
        opad_key[x] ^= normalized_key[x];
    }

    // Continue the seed derivation process
    uchar seed[64] = { 0 };
    uchar sha512_result[64] = { 0 };
    uchar key_previous_concat[256] = { 0 };
    uchar salt[12] = { 109, 110, 101, 109, 111, 110, 105, 99, 0, 0, 0, 1 };
    for(int x = 0; x < 128; x++) {
        key_previous_concat[x] = ipad_key[x];
    }
    for(int x = 0; x < 12; x++) {
        key_previous_concat[x + 128] = salt[x];
    }

    sha512(&key_previous_concat, 140, &sha512_result);
    copy_pad_previous(&opad_key, &sha512_result, &key_previous_concat);
    sha512(&key_previous_concat, 192, &sha512_result);
    xor_seed_with_round(&seed, &sha512_result);

    for(int x = 1; x < 2048; x++) {
        copy_pad_previous(&ipad_key, &sha512_result, &key_previous_concat);
        sha512(&key_previous_concat, 192, &sha512_result);
        copy_pad_previous(&opad_key, &sha512_result, &key_previous_concat);
        sha512(&key_previous_concat, 192, &sha512_result);
        xor_seed_with_round(&seed, &sha512_result);
    }
}

This was my work, test it to see if everything is running fine and let me know