Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openzeppelin merkletree solidity verify? #38

Open
duktig666 opened this issue Jan 4, 2024 · 2 comments
Open

openzeppelin merkletree solidity verify? #38

duktig666 opened this issue Jan 4, 2024 · 2 comments

Comments

@duktig666
Copy link

solidity:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {MerkleProof} from "openzeppelin-contracts/utils/cryptography/MerkleProof.sol";

contract MerkleTreeUtil {
    function verifyMerkle(bytes32[] memory merkleProof, bytes32 _merkleRoot, address minterAddress)
        internal
        pure
        returns (bool)
    {
        return MerkleProof.verify(merkleProof, _merkleRoot, keccak256(abi.encode(minterAddress)));
    }
}

contract address:https://holesky.etherscan.io/address/0x2468f946031a903a1047bE72258c86d4fAA489c6#readContract

The following writing method cannot be validated on Solidity:

go:

import (
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/pkg/errors"
	"github.com/stretchr/testify/require"
	"nft-common/cryptor"
	"testing"

	mt "github.com/txaty/go-merkletree"
)

var leaves = []string{
	"0x6EFd53BA1f3DD573EAc80B82b4B6266F6dEFA4bD",
	"0x0F9C1bcC4BA8a85194ABe5B14565eB43CDEe2ed7",
	"0xf852007A9Cb2771a34DAF6fc5d2AD430a638beae",
	"0x2bF965771801faC320eBC067AF5aEC1a0AB62fA2",
	"0x560950f740916F1c6D0750EC1b7ad2bd98691BC7",
	"0x3535d10Fc0E85fDBC810bF828F02C9BcB7C2EBA8",
	"0x680A72cB90322537c664Dedd5F6A1423eD892F0F",
	"0xe583DC38863aB4b5A94da77A6628e2119eaD4B18",
	"0x892e7c8C5E716e17891ABf9395a0de1f2fc84786",
}

func testLeafHashFunc(address common.Address) ([]byte, error) {
	codeBytes, err := cryptor.AbiCoder([]string{"address"}, []interface{}{address})
	if err != nil {
		return nil, errors.Wrap(err, "AbiCoder")
	}
	hash := crypto.Keccak256Hash(codeBytes)
	return hash.Bytes(), nil
}

func TestLeafHash(t *testing.T) {
	for _, leaf := range leaves {
		hashBytes, err := testLeafHashFunc(common.HexToAddress(leaf))
		require.NoError(t, err)
		t.Log(common.BytesToHash(hashBytes).Hex())
	}
}

func LeafHashFunc(addressByte []byte) ([]byte, error) {
	address := common.BytesToAddress(addressByte)
	codeBytes, err := cryptor.AbiCoder([]string{"address"}, []interface{}{address})
	if err != nil {
		return nil, errors.Wrap(err, "AbiCoder")
	}
	hash := crypto.Keccak256Hash(codeBytes)
	return hash.Bytes(), nil
}

type Leave string

func (l Leave) Serialize() ([]byte, error) {
	return hexutil.Decode(string(l))
}

func TestOpenzeppelinSortMerkleTree(t *testing.T) {
	config := &mt.Config{
		HashFunc:           LeafHashFunc,
		NumRoutines:        0,
		Mode:               mt.ModeProofGenAndTreeBuild,
		RunInParallel:      false,
		SortSiblingPairs:   true,
		DisableLeafHashing: false,
	}

	dataBlocks := make([]mt.DataBlock, 0, len(leaves))
	for _, leaf := range leaves {
		dataBlocks = append(dataBlocks, Leave(leaf))
	}

	merkleTree, err := mt.New(config, dataBlocks)
	require.NoError(t, err)

	root := hexutil.Encode(merkleTree.Root)
	t.Log(root)

	proofs := merkleTree.Proofs
	t.Log(ProofsStrings(proofs))

	node := Leave("0x6EFd53BA1f3DD573EAc80B82b4B6266F6dEFA4bD")
	proof, err := merkleTree.Proof(node)
	require.NoError(t, err)
	t.Log(ProofStrings(proof))

	verify, err := merkleTree.Verify(node, proof)
	require.NoError(t, err)
	require.True(t, verify)
}

func ProofStrings(p *mt.Proof) []string {
	res := make([]string, 0)
	for _, sibling := range p.Siblings {
		proof := hexutil.Encode(sibling)
		res = append(res, proof)
	}
	return res
}

func ProofsStrings(p []*mt.Proof) [][]string {
	res := make([][]string, 0)
	for _, proof := range p {
		pp := make([]string, 0)
		for _, sibling := range proof.Siblings {
			pHex := hexutil.Encode(sibling)
			pp = append(pp, pHex)
		}
		res = append(res, pp)
	}
	return res
}
@duktig666
Copy link
Author

But I use TS's merkletreejs to implement it and it can be verified that it passes:

ts:

import {MerkleTree} from "merkletreejs";
import {keccak256, defaultAbiCoder} from "ethers/lib/utils";
import {ethers} from "ethers";

const SHA256 = require('crypto-js/sha256')

const arr0 = [
    "0x6EFd53BA1f3DD573EAc80B82b4B6266F6dEFA4bD",
    "0x0F9C1bcC4BA8a85194ABe5B14565eB43CDEe2ed7",
    "0xf852007A9Cb2771a34DAF6fc5d2AD430a638beae",
    "0x2bF965771801faC320eBC067AF5aEC1a0AB62fA2",
    "0x560950f740916F1c6D0750EC1b7ad2bd98691BC7",
    "0x3535d10Fc0E85fDBC810bF828F02C9BcB7C2EBA8",
    "0x680A72cB90322537c664Dedd5F6A1423eD892F0F",
    "0xe583DC38863aB4b5A94da77A6628e2119eaD4B18",
    "0x892e7c8C5E716e17891ABf9395a0de1f2fc84786",
];

// const arr1 = [
//     1, 2, 3, 4, 5
// ];
//
//
// const arr2 = [
//     "1",
//     "2",
//     "3",
//     "4",
//     "5",
// ];
//
// const arr3 = [
//     "dog", "cat", "mouse", "horse"
// ];

describe("merkle tree test", () => {

    // var arr = arr0.map(x => SHA256(x))
    let merkleTree = new MerkleTree(arr0, keccak256);
    const hexRoot = merkleTree.getHexRoot();

    it("merkle root", () => {
        console.log(hexRoot);
    });

    it("merkle verify", () => {
        const proof = merkleTree.getHexProof("0x892e7c8C5E716e17891ABf9395a0de1f2fc84786");

        // const verify = merkleTree.verify(proof, leaf, hexRoot);
        // expect(verify).toBe(true);
        console.log(proof);
    });
});


const createMerkleTree = (leaves: Buffer[]) =>
    new MerkleTree(leaves, keccak256, {
        hashLeaves: true,
        // sortLeaves: true,
        sortPairs: true,
    });

const toPaddedBuffer = (data: any) =>
    Buffer.from(
        ethers.BigNumber.from(data).toHexString().slice(2).padStart(64, "0"),
        "hex"
    );

const allowListElementsBuffer = (
    leaves: Array<[minter: string]>
) =>
    leaves.map(([minter]) =>
        Buffer.concat(
            [
                minter,
            ].map(toPaddedBuffer)
        )
    );


describe("opensea merkle tree test", () => {
    // Encode the minter address and mintParams.
    const elementsBuffer = allowListElementsBuffer([
        ["0x6EFd53BA1f3DD573EAc80B82b4B6266F6dEFA4bD"],
        ["0x0F9C1bcC4BA8a85194ABe5B14565eB43CDEe2ed7"],
        ["0xf852007A9Cb2771a34DAF6fc5d2AD430a638beae"],
        ["0x2bF965771801faC320eBC067AF5aEC1a0AB62fA2"],
        ["0x560950f740916F1c6D0750EC1b7ad2bd98691BC7"],
        ["0x3535d10Fc0E85fDBC810bF828F02C9BcB7C2EBA8"],
        ["0x680A72cB90322537c664Dedd5F6A1423eD892F0F"],
        ["0xe583DC38863aB4b5A94da77A6628e2119eaD4B18"],
        ["0x892e7c8C5E716e17891ABf9395a0de1f2fc84786"],
    ]);

    // Construct a merkle tree from the allow list elements.
    const merkleTree = createMerkleTree(elementsBuffer);

    // Store the merkle root.
    const root = merkleTree.getHexRoot();

    // const node = Buffer.concat(
    //     [
    //         "0x892e7c8C5E716e17891ABf9395a0de1f2fc84786",
    //     ].map(toPaddedBuffer)
    // )
    //
    // var node2 = Buffer.from(keccak256(elementsBuffer[0]));
    //
    // // Get the leaf at index 0.
    // const leafIndex = merkleTree.getLeafIndex(node2);
    const leaf = merkleTree.getLeaf(0);


    // Get the proof of the leaf to pass into the transaction.
    const proof = merkleTree.getHexProof(leaf);

    it("merkle log", () => {
        console.log(root);
        // console.log(leafIndex);
        console.log(leaf);
        console.log(leaf.toString());
        console.log(proof);
    });

    it("verify", () => {
        var verify = merkleTree.verify(proof, keccak256(elementsBuffer[0]), root)
        console.log(verify);
        console.log(keccak256(elementsBuffer[0]));
    });

    it("verify2", () => {
        const node = Buffer.concat(
            [
                "0x6EFd53BA1f3DD573EAc80B82b4B6266F6dEFA4bD",
            ].map(toPaddedBuffer)
        )

        console.log(keccak256(node));
    });

    it("proofs", () => {
        for (let i = 0; i < 9; i++) {
            console.log("proof", i);
            console.log(merkleTree.getHexProof(merkleTree.getLeaf(i)));
        }
    });
});

@txaty
Copy link
Owner

txaty commented Feb 17, 2024

Hi~ Thanks for using this library and providing feedbacks.

Seems like there are some issues in LeafHashFunc().

Test TestOpenzeppelinSortMerkleTree can pass when changing only the hash function to the default one or replacing LeafHashFunc() with:

func LeafHashFunc(addressByte []byte) ([]byte, error) {
	hash := crypto.Keccak256Hash(addressByte)
	return hash.Bytes(), nil
}

Repository owner deleted a comment Feb 20, 2024
Repository owner deleted a comment Feb 20, 2024
Repository owner deleted a comment Feb 20, 2024
Repository owner deleted a comment from DrakoAI Feb 21, 2024
Repository owner deleted a comment Feb 23, 2024
Repository owner deleted a comment from DavideStagni Mar 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@txaty @duktig666 and others