github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/scripts/go-ffi/merkle.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"strconv"
     8  
     9  	"github.com/ethereum-optimism/optimism/op-challenger/game/keccak/merkle"
    10  
    11  	"github.com/ethereum/go-ethereum/accounts/abi"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/common/hexutil"
    14  	"github.com/ethereum/go-ethereum/crypto"
    15  )
    16  
    17  // VerifyMerkleProof verifies a merkle proof against the root hash and the leaf hash.
    18  // Reference: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_valid_merkle_branch
    19  func VerifyMerkleProof(root, leaf common.Hash, index uint64, proof [merkle.BinaryMerkleTreeDepth]common.Hash) bool {
    20  	value := leaf
    21  	for i := 0; i < merkle.BinaryMerkleTreeDepth; i++ {
    22  		if ((index >> i) & 1) == 1 {
    23  			value = crypto.Keccak256Hash(proof[i][:], value[:])
    24  		} else {
    25  			value = crypto.Keccak256Hash(value[:], proof[i][:])
    26  		}
    27  	}
    28  	return value == root
    29  }
    30  
    31  const (
    32  	// GenProof generates a merkle proof for a given leaf index by reconstructing the merkle tree from the passed
    33  	// leaves.
    34  	genProof = "gen_proof"
    35  )
    36  
    37  var (
    38  	rootAndProof, _ = abi.NewType("tuple", "", []abi.ArgumentMarshaling{
    39  		{Name: "root", Type: "bytes32"},
    40  		{Name: "proof", Type: "bytes32[]"},
    41  	})
    42  
    43  	merkleEncoder = abi.Arguments{
    44  		{Type: rootAndProof},
    45  	}
    46  )
    47  
    48  // DiffMerkle generates an abi-encoded `merkleTestCase` of a specified variant.
    49  func DiffMerkle() {
    50  	variant := os.Args[2]
    51  	if len(variant) == 0 {
    52  		log.Fatal("Must pass a variant to the merkle diff tester!")
    53  	}
    54  
    55  	switch variant {
    56  	case genProof:
    57  		if len(os.Args) < 5 {
    58  			log.Fatal("Invalid arguments to `gen_proof` variant.")
    59  		}
    60  
    61  		rawLeaves, err := hexutil.Decode(os.Args[3])
    62  		if err != nil {
    63  			log.Fatal("Failed to decode leaves: ", err)
    64  		}
    65  		index, err := strconv.ParseInt(os.Args[4], 10, 64)
    66  		if err != nil {
    67  			log.Fatal("Failed to parse leaf index: ", err)
    68  		}
    69  		merkleTree := merkle.NewBinaryMerkleTree()
    70  
    71  		// Append all leaves to the merkle tree.
    72  		for i := 0; i < len(rawLeaves)/32; i++ {
    73  			leaf := common.BytesToHash(rawLeaves[i<<5 : (i+1)<<5])
    74  			merkleTree.AddLeaf(leaf)
    75  		}
    76  
    77  		// Generate the proof for the given index.
    78  		proof := merkleTree.ProofAtIndex(uint64(index))
    79  
    80  		// Generate the merkle root.
    81  		root := merkleTree.RootHash()
    82  
    83  		// Return "abi.encode(root, proof)"
    84  		packed, err := merkleEncoder.Pack(struct {
    85  			Root  common.Hash
    86  			Proof [merkle.BinaryMerkleTreeDepth]common.Hash
    87  		}{
    88  			Root:  root,
    89  			Proof: proof,
    90  		})
    91  		if err != nil {
    92  			log.Fatal("Failed to ABI encode root and proof: ", err)
    93  		}
    94  		fmt.Print(hexutil.Encode(packed[32:]))
    95  	default:
    96  		log.Fatal("Invalid variant passed to merkle diff tester!")
    97  	}
    98  }