diff --git a/config/features/config.go b/config/features/config.go index 3dca3c76f7c8..d97ca15c97ed 100644 --- a/config/features/config.go +++ b/config/features/config.go @@ -69,6 +69,7 @@ type Flags struct { DisableResourceManager bool // Disables running the node with libp2p's resource manager. DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks + EnableHashtree bool // Enables usage of the hashtree library for hashing EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails PrepareAllPayloads bool // PrepareAllPayloads informs the engine to prepare a block on every slot. @@ -233,6 +234,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error { logEnabled(enableFullSSZDataLogging) cfg.EnableFullSSZDataLogging = true } + if ctx.IsSet(enableHashtree.Name) { + logEnabled(enableHashtree) + cfg.EnableHashtree = true + } cfg.EnableVerboseSigVerification = true if ctx.IsSet(disableVerboseSigVerification.Name) { logEnabled(disableVerboseSigVerification) diff --git a/config/features/flags.go b/config/features/flags.go index 2b263eb17317..78eb5c44a267 100644 --- a/config/features/flags.go +++ b/config/features/flags.go @@ -135,6 +135,10 @@ var ( Name: "enable-beacon-rest-api", Usage: "(Experimental): Enables of the beacon REST API when querying a beacon node.", } + enableHashtree = &cli.BoolFlag{ + Name: "enable-hashtree", + Usage: "(Experimental): Enables the hashthree hashing library.", + } disableVerboseSigVerification = &cli.BoolFlag{ Name: "disable-verbose-sig-verification", Usage: "Disables identifying invalid signatures if batch verification fails when processing block.", @@ -215,6 +219,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c disablePeerScorer, disableBroadcastSlashingFlag, enableSlasherFlag, + enableHashtree, enableHistoricalSpaceRepresentation, disableStakinContractCheck, SaveFullExecutionPayloads, diff --git a/consensus-types/blocks/BUILD.bazel b/consensus-types/blocks/BUILD.bazel index 32ba9157fe49..1329786eac3e 100644 --- a/consensus-types/blocks/BUILD.bazel +++ b/consensus-types/blocks/BUILD.bazel @@ -19,6 +19,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//beacon-chain/state/stateutil:go_default_library", + "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types:go_default_library", diff --git a/consensus-types/blocks/kzg.go b/consensus-types/blocks/kzg.go index e33d4dd7e034..3e4e44af8a98 100644 --- a/consensus-types/blocks/kzg.go +++ b/consensus-types/blocks/kzg.go @@ -3,6 +3,7 @@ package blocks import ( "github.com/pkg/errors" "github.com/prysmaticlabs/gohashtree" + "github.com/prysmaticlabs/prysm/v5/config/features" field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" @@ -39,7 +40,11 @@ func VerifyKZGInclusionProof(blob ROBlob) error { return errInvalidBodyRoot } chunks := makeChunk(blob.KzgCommitment) - gohashtree.HashChunks(chunks, chunks) + if features.Get().EnableHashtree { + hashtree.HashChunks(chunks, chunks) + } else { + gohashtree.HashChunks(chunks, chunks) + } verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof) if !verified { return errInvalidInclusionProof diff --git a/crypto/hash/htr/BUILD.bazel b/crypto/hash/htr/BUILD.bazel index 968cb7c683b5..2a0e62a67882 100644 --- a/crypto/hash/htr/BUILD.bazel +++ b/crypto/hash/htr/BUILD.bazel @@ -5,7 +5,11 @@ go_library( srcs = ["hashtree.go"], importpath = "github.com/prysmaticlabs/prysm/v5/crypto/hash/htr", visibility = ["//visibility:public"], - deps = ["@com_github_prysmaticlabs_gohashtree//:go_default_library"], + deps = [ + "//config/features:go_default_library", + "@com_github_prysmaticlabs_gohashtree//:go_default_library", + "@com_github_prysmaticlabs_hashtree//:go_default_library", + ], ) go_test( diff --git a/crypto/hash/htr/hashtree.go b/crypto/hash/htr/hashtree.go index 1ffb68b03803..76c15b2a57a5 100644 --- a/crypto/hash/htr/hashtree.go +++ b/crypto/hash/htr/hashtree.go @@ -5,13 +5,20 @@ import ( "sync" "github.com/prysmaticlabs/gohashtree" + "github.com/prysmaticlabs/hashtree" + "github.com/prysmaticlabs/prysm/v5/config/features" ) const minSliceSizeToParallelize = 5000 func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGroup) { defer wg.Done() - err := gohashtree.Hash(outputList, inputList) + var err error + if features.Get().EnableHashtree { + err = hashtree.Hash(outputList, inputList) + } else { + err = gohashtree.Hash(outputList, inputList) + } if err != nil { panic(err) } @@ -38,7 +45,12 @@ func VectorizedSha256(inputList [][32]byte) [][32]byte { for j := 0; j < n; j++ { go hashParallel(inputList[j*2*groupSize:(j+1)*2*groupSize], outputList[j*groupSize:], &wg) } - err := gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:]) + var err error + if features.Get().EnableHashtree { + err = hashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:]) + } else { + err = gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:]) + } if err != nil { panic(err) } diff --git a/crypto/hash/htr/hashtree_test.go b/crypto/hash/htr/hashtree_test.go index db5f44a64458..38abe6576856 100644 --- a/crypto/hash/htr/hashtree_test.go +++ b/crypto/hash/htr/hashtree_test.go @@ -4,6 +4,7 @@ import ( "sync" "testing" + "github.com/prysmaticlabs/prysm/v5/config/features" "github.com/prysmaticlabs/prysm/v5/testing/require" ) @@ -25,3 +26,27 @@ func Test_VectorizedSha256(t *testing.T) { require.Equal(t, r, hash2[i]) } } + +func Test_VectorizedSha256_hashtree_enabled(t *testing.T) { + resetCfg := features.InitWithReset(&features.Flags{ + EnableHashtree: true, + }) + defer resetCfg() + + largeSlice := make([][32]byte, 32*minSliceSizeToParallelize) + secondLargeSlice := make([][32]byte, 32*minSliceSizeToParallelize) + hash1 := make([][32]byte, 16*minSliceSizeToParallelize) + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + tempHash := VectorizedSha256(largeSlice) + copy(hash1, tempHash) + }() + wg.Wait() + hash2 := VectorizedSha256(secondLargeSlice) + require.Equal(t, len(hash1), len(hash2)) + for i, r := range hash1 { + require.Equal(t, r, hash2[i]) + } +} diff --git a/deps.bzl b/deps.bzl index 0a341df4a79c..f4fcf44a9f40 100644 --- a/deps.bzl +++ b/deps.bzl @@ -4810,3 +4810,13 @@ def prysm_deps(): build_file = "//third_party:blst/blst.BUILD", sha256 = "132124c074e59ead77e1828cc54b587a182ea67b781b72198e802af4696d78fe", ) + + http_archive( + name = "com_github_prysmaticlabs_hashtree", + urls = [ + "https://github.com/prysmaticlabs/hashtree/archive/refs/tags/v0.2.0.tar.gz", + ], + strip_prefix = "hashtree-0.2.0", + build_file = "//third_party:hashtree/hashtree.BUILD", + sha256 = "26e6e14712040be81b5c9c08dc0ad2d48e03f2f9032806a76e98e438af10c1e0", + ) diff --git a/third_party/hashtree/hashtree.BUILD b/third_party/hashtree/hashtree.BUILD new file mode 100644 index 000000000000..e13b8191e3e5 --- /dev/null +++ b/third_party/hashtree/hashtree.BUILD @@ -0,0 +1,64 @@ +load("@prysm//tools/go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "bindings.go", + "sha256_1_generic.go", + "bindings_amd64.go", + "bindings_arm64.go", + "wrapper_arm64.s", + "wrapper_linux_amd64.s", + "wrapper_windows_amd64.s", + ], + deps = select({ + "@io_bazel_rules_go//go/platform:amd64": ["@com_github_klauspost_cpuid_v2//:cpuid"], + "@io_bazel_rules_go//go/platform:arm64": ["@com_github_klauspost_cpuid_v2//:cpuid"], + "//conditions:default": [] + }), + cgo = True, + copts = [ + "-g -Wall -Werror -fpic", + "-O2", + "-Isrc", + ], + cdeps = [":hashtree"], + importpath = "github.com/prysmaticlabs/hashtree", + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = [ + "bindings_test.go", + ], + embed = [":go_default_library"], +) + +cc_library( + name = "hashtree", + srcs = [ + "src/hashtree.c", + "src/sha256_sse_x1.S", + "src/sha256_avx_x1.S", + "src/sha256_avx_x4.S", + "src/sha256_avx_x8.S", + "src/sha256_avx_x16.S", + "src/sha256_shani.S", + "src/sha256_armv8_crypto.S", + "src/sha256_armv8_neon_x1.S", + "src/sha256_armv8_neon_x4.S", + ], + hdrs = [ + "src/hashtree.h", + ], + copts = [ + "-g -Wall -Werror -fpic", + "-O2", + "-Isrc", + "-fno-integrated-as", + ], + visibility = ["//visibility:public"], + linkstatic = True, +)