Простая реализация дерева Меркла в java

Я пытаюсь написать простую реализацию дерева Меркле очень на Java.

Я использую значения txids в блок 170 в цепочке биткойнов для справки, поэтому я могу видеть, каким должен быть правильный результат.

txids, соответствующие этому блоку, следующие:

b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082
f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16

Насколько я понимаю, реализация биткойн-дерева Меркла работает следующим образом:

  1. разделить транзакции в блоке на пары
  2. перестановка байтов в txids
  3. объединить txids
  4. двойной хеш конкатенированных пар

С оговоркой:

If there's no additional pairs of txids, concatenate the result of the first pair after double hashing with itself and repeat

Мой код находится в операторе switch, который выглядит так:

case "test merkle root": {
    // txid A
    String A = "b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082";

    // txid A byte-swapped
    String A_little = MainChain.swapEndianness(A);

    // txid B
    String B = "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16";

    // txid B byte-swapped
    String B_little = MainChain.swapEndianness(B);

    // txid A + B concatenated
    String AB_little = A_little + B_little;

    // double hash of byte-swapped concatenated A+B
    String ABdoubleHash =  SHA256.generateSHA256Hash(SHA256.generateSHA256Hash(AB_little));

    // double hash concatenated with itself
    String ABAB_little = ABdoubleHash + ABdoubleHash;

    // double hash of self-concatenated double-hashed txid
    String merkleRootLittleEndian = SHA256.generateSHA256Hash(SHA256.generateSHA256Hash(ABAB_little));

    // print result byte-swapped back to big-endian
    System.out.println("Merkle root: " + MainChain.swapEndianness(merkleRootLittleEndian));
}

Метод swapEndianness, который я написал, не является настоящим обменом на уровне байтов, а вместо этого просто меняет порядок строки, он выглядит так:

public static String swapEndianness(String hash) {
        char[] hashAsCharArray = hash.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = hash.length() - 1; i > 0; i-=2) {
            sb.append(hashAsCharArray[i - 1]);
            sb.append(hashAsCharArray[i]);
        }
        return sb.toString();
    }

Ожидаемый результат для корня меркла этих двух txid:

7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff

Однако в результате я получаю следующее:

3b40cab1157838cc41b08e27641f65d245957ab07b3504d94bc2d355abaed06c

Я не получаю ожидаемого результата, потому что я обманываю, когда выполняю замену байтов, потому что я пропускаю шаг или потому что у меня есть ошибка в моем коде (или какая-то их комбинация)? Любая помощь будет оценена по достоинству!

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
3 199
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не понимаете, что такое byte[] в Java. Строки в вашем примере представляют собой «шестнадцатеричные» представления байта []. См. Как инициализировать массив байтов в Java?

public class MerkleTree {
    static MessageDigest digest;
    public static void main(String[] args) throws NoSuchAlgorithmException {
        digest = MessageDigest.getInstance("SHA-256");
        new MerkleTree().run();
    }
    private void run() {
        // txid A
        byte[] A = hexStringToByteArray("b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082");
        System.out.println(Arrays.toString(A));
        // txid A byte-swapped
        byte[] A_little = swapEndianness(A);
        System.out.println(Arrays.toString(A_little));

        // txid B
        byte[] B = hexStringToByteArray("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16");
        System.out.println(Arrays.toString(B));

        // txid B byte-swapped
        byte[] B_little = swapEndianness(B);
        System.out.println(Arrays.toString(B_little));

        // txid A + B concatenated
        byte[] AB_little = Arrays.copyOf(A_little, A_little.length + B_little.length);
        System.arraycopy(B_little, 0, AB_little, A_little.length, B_little.length);
        System.out.println(Arrays.toString(AB_little));

        // double hash of byte-swapped concatenated A+B
        byte[] ABdoubleHash = SHA256(SHA256(AB_little));
        System.out.println(Arrays.toString(ABdoubleHash));

        // print result byte-swapped back to big-endian
        byte[] result = swapEndianness(ABdoubleHash);
        System.out.println(Arrays.toString(result));
        System.out.println(getHex(result));         
    }
    byte[] swapEndianness(byte[] hash) {
        byte[] result = new byte[hash.length];
        for (int i = 0; i < hash.length; i++) {
            result[i] = hash[hash.length-i-1];
        }
        return result;
    }
    byte[] SHA256(byte[] obytes) {
        return digest.digest(obytes);
    }
    byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
    private static final String    HEXES    = "0123456789abcdef";
    String getHex(byte[] raw) {
        final StringBuilder hex = new StringBuilder(2 * raw.length);
        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
        }
        return hex.toString();
    }
} 

Наконец, обратитесь к Код Java для преобразования байта в шестнадцатеричный

Обновлено: Это было бы немного лучше для ресурсов, так как вы часто хотите делать такие вещи.

    // txid A byte-swapped
    byte[] A = swapEndianness(
            hexStringToByteArray("b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082")
        );
    // txid B byte-swapped
    byte[] B = swapEndianness(
            hexStringToByteArray("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16")
        );
    // txid A + B concatenated
    byte[] AB = Arrays.copyOf(A, A.length + B.length);
    System.arraycopy(B, 0, AB, A.length, B.length);

    // print result byte-swapped back to big-endian
    String result = getHex(swapEndianness(SHA256(SHA256(AB))));
    System.out.println(result);         
    }
    byte[] swapEndianness(byte[] hash) {
        for (int i = 0; i < hash.length/2; i++) {
            byte t = hash[hash.length-i-1];
            hash[hash.length-i-1] = hash[i]; 
            hash[i] = t; 
        }
        return hash;
    }

Я знаю, что такое byte[] в java и на любом другом языке, который поддерживает его как тип, если уж на то пошло. Я специально сказал, что я «обманул», используя только строки, и сделал слово очень в утверждении «очень простой» жирным шрифтом намеренно, потому что я новичок и способен только на простые реализации. Спасибо за ваш ответ, так как это именно то, что мне нужно, и явно хорошо продумано, но я бы хотел, чтобы вы были более поощряющими в распространении своих знаний.

apt-getschwifty 31.05.2019 02:29

Инжиниринг — это решение проблем, которые часто не являются «очень простыми». youtube.com/watch?v=82LXZqfABZw В любом случае, не беспокойся, приятель, сойдет.

K.Nicholas 31.05.2019 03:29

Вы знаете, что они говорят, каждый день - учебный день. Ценю тебя мужик!

apt-getschwifty 31.05.2019 03:44

Другие вопросы по теме