【问题标题】:A simple merkle-tree implementation in javajava中一个简单的merkle-tree实现
【发布时间】:2019-10-16 14:41:44
【问题描述】:

我正在尝试用 Java 编写一个非常简单的默克尔树实现。

我正在使用比特币区块链上block 170 中的 txid 值作为参考,所以我可以看到正确的结果应该是什么。

该区块对应的txid如下:

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方法并不是真正的‘字节级’交换,而是只是改变了String的顺序,看起来是这样的:

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的merkle root的预期结果是:

7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff

但是,我最终得到的结果是:

3b40cab1157838cc41b08e27641f65d245957ab07b3504d94bc2d355abaed06c

我没有得到我期望的结果是因为我在进行字节交换时作弊,是因为我错过了一个步骤,还是因为我的代码中有错误(或这些错误的某种组合)?任何帮助将不胜感激!

【问题讨论】:

    标签: java merkle-tree


    【解决方案1】:

    您不了解 Java 中的 byte[] 是什么。您示例中的字符串是字节 [] 的“十六进制”表示。见How do I initialize a byte array in 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 code To convert byte to Hexadecimal

    编辑:这在资源上会好一点,因为你经常想做这种事情。

        // 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 中是什么,以及在其他所有支持它作为类型的语言中。我特别说我只使用字符串来“作弊”,并故意将“非常简单”语句中的 very 一词加粗,因为我是新手,只能进行简单的实现。感谢您的回复,因为这正是我所需要的,而且显然是精心制作的,但我希望您在传播知识方面更加鼓励。
    • 工程是关于解决通常不是“非常简单”的问题。 youtube.com/watch?v=82LXZqfABZw无论如何,伙计,不用担心,会的。
    • 你知道他们说什么,每天都是上学日。欣赏你的男人!
    猜你喜欢
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    相关资源
    最近更新 更多