From ab1b3b486324422b4c48ed146c04d405a6d70143 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Mon, 15 Mar 2021 10:43:32 +0300 Subject: [PATCH] Add antireplay cache --- antireplay/noop.go | 11 +++++++++++ antireplay/noop_test.go | 26 ++++++++++++++++++++++++++ antireplay/stable_bloom_filter.go | 24 ++++++++++++++++++++++++ antireplay/stable_bloom_filter_test.go | 26 ++++++++++++++++++++++++++ go.mod | 2 ++ go.sum | 4 ++++ mtglib/init.go | 4 ++++ 7 files changed, 97 insertions(+) create mode 100644 antireplay/noop.go create mode 100644 antireplay/noop_test.go create mode 100644 antireplay/stable_bloom_filter.go create mode 100644 antireplay/stable_bloom_filter_test.go diff --git a/antireplay/noop.go b/antireplay/noop.go new file mode 100644 index 0000000..8613e40 --- /dev/null +++ b/antireplay/noop.go @@ -0,0 +1,11 @@ +package antireplay + +import "github.com/9seconds/mtg/v2/mtglib" + +type noop struct{} + +func (n noop) SeenBefore(_ []byte) bool { return false } + +func NewNoop() mtglib.AntiReplayCache { + return noop{} +} diff --git a/antireplay/noop_test.go b/antireplay/noop_test.go new file mode 100644 index 0000000..b78c48d --- /dev/null +++ b/antireplay/noop_test.go @@ -0,0 +1,26 @@ +package antireplay_test + +import ( + "testing" + + "github.com/9seconds/mtg/v2/antireplay" + "github.com/stretchr/testify/suite" +) + +type NoopTestSuite struct { + suite.Suite +} + +func (suite *NoopTestSuite) TestOp() { + filter := antireplay.NewNoop() + + suite.False(filter.SeenBefore([]byte{1, 2, 3})) + suite.False(filter.SeenBefore([]byte{4, 5, 6})) + suite.False(filter.SeenBefore([]byte{1, 2, 3})) + suite.False(filter.SeenBefore([]byte{4, 5, 6})) +} + +func TestNoop(t *testing.T) { + t.Parallel() + suite.Run(t, &NoopTestSuite{}) +} diff --git a/antireplay/stable_bloom_filter.go b/antireplay/stable_bloom_filter.go new file mode 100644 index 0000000..5ab15f3 --- /dev/null +++ b/antireplay/stable_bloom_filter.go @@ -0,0 +1,24 @@ +package antireplay + +import ( + "github.com/9seconds/mtg/v2/mtglib" + "github.com/OneOfOne/xxhash" + boom "github.com/tylertreat/BoomFilters" +) + +type stableBloomFilter struct { + filter boom.StableBloomFilter +} + +func (s *stableBloomFilter) SeenBefore(digest []byte) bool { + return s.filter.TestAndAdd(digest) +} + +func NewStableBloomFilter(byteSize uint, errorRate float64) mtglib.AntiReplayCache { + sf := boom.NewDefaultStableBloomFilter(byteSize*8, errorRate) // nolint: gomnd + sf.SetHash(xxhash.New64()) + + return &stableBloomFilter{ + filter: *sf, + } +} diff --git a/antireplay/stable_bloom_filter_test.go b/antireplay/stable_bloom_filter_test.go new file mode 100644 index 0000000..accb590 --- /dev/null +++ b/antireplay/stable_bloom_filter_test.go @@ -0,0 +1,26 @@ +package antireplay_test + +import ( + "testing" + + "github.com/9seconds/mtg/v2/antireplay" + "github.com/stretchr/testify/suite" +) + +type StableBloomFilterTestSuite struct { + suite.Suite +} + +func (suite *StableBloomFilterTestSuite) TestOp() { + filter := antireplay.NewStableBloomFilter(500, 0.001) + + suite.False(filter.SeenBefore([]byte{1, 2, 3})) + suite.False(filter.SeenBefore([]byte{4, 5, 6})) + suite.True(filter.SeenBefore([]byte{1, 2, 3})) + suite.True(filter.SeenBefore([]byte{4, 5, 6})) +} + +func TestStableBloomFilter(t *testing.T) { + t.Parallel() + suite.Run(t, &StableBloomFilterTestSuite{}) +} diff --git a/go.mod b/go.mod index 3f1b78b..1438615 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/9seconds/mtg/v2 go 1.16 require ( + github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/alecthomas/kong v0.2.16 github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 @@ -15,6 +16,7 @@ require ( github.com/rs/zerolog v1.20.0 // indirect github.com/stretchr/objx v0.3.0 // indirect github.com/stretchr/testify v1.7.0 + github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c // indirect github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect diff --git a/go.sum b/go.sum index e6d0a7f..5f3cd5b 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/alecthomas/kong v0.2.16 h1:F232CiYSn54Tnl1sJGTeHmx4vJDNLVP2b9yCVMOQwHQ= github.com/alecthomas/kong v0.2.16/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4= @@ -40,6 +42,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c h1:pGEq55pv/5i+G/Dy+kDsUugzvg6R02jzegxtrwOhE7A= +github.com/tylertreat/BoomFilters v0.0.0-20200520150052-42a7b4300c0c/go.mod h1:OYRfF6eb5wY9VRFkXJH8FFBi3plw2v+giaIu7P054pM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= diff --git a/mtglib/init.go b/mtglib/init.go index 1c50d61..2bb6975 100644 --- a/mtglib/init.go +++ b/mtglib/init.go @@ -17,6 +17,10 @@ type Network interface { IdleTimeout() time.Duration } +type AntiReplayCache interface { + SeenBefore(data []byte) bool +} + type Logger interface { Named(name string) Logger