event.CheckID()

absurd performance increase benefit over a naïve id comparison!

goos: linux
goarch: amd64
pkg: github.com/nbd-wtf/go-nostr
cpu: AMD Ryzen 3 3200G with Radeon Vega Graphics
BenchmarkIDCheck/naïve-4          	 1478547	       802.9 ns/op	     488 B/op	      15 allocs/op
BenchmarkIDCheck/big_brain-4      	 1673341	       715.3 ns/op	     358 B/op	      12 allocs/op
This commit is contained in:
fiatjaf 2024-09-14 10:55:16 -03:00
parent a094f3a9d2
commit b5f8d48f79
2 changed files with 61 additions and 1 deletions

View File

@ -35,6 +35,28 @@ func (evt *Event) GetID() string {
return hex.EncodeToString(h[:])
}
// CheckID checks if the implied ID matches the given ID
func (evt *Event) CheckID() bool {
ser := evt.Serialize()
h := sha256.Sum256(ser)
const hextable = "0123456789abcdef"
for i := 0; i < 32; i++ {
b := hextable[h[i]>>4]
if b != evt.ID[i*2] {
return false
}
b = hextable[h[i]&0x0f]
if b != evt.ID[i*2+1] {
return false
}
}
return true
}
// Serialize outputs a byte array that can be hashed/signed to identify/authenticate.
// JSON encoding as defined in RFC4627.
func (evt *Event) Serialize() []byte {

View File

@ -2,9 +2,12 @@ package nostr
import (
"encoding/json"
"fmt"
"math/rand/v2"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestEventParsingAndVerifying(t *testing.T) {
@ -117,7 +120,6 @@ func TestEventSerializationWithExtraFields(t *testing.T) {
assert.Condition(t, func() (success bool) {
if evt.GetExtra("glub").(bool) != evt.GetExtraBoolean("glub") || evt.GetExtraBoolean("glub") != true {
return false
}
return true
@ -132,3 +134,39 @@ func mustSignEvent(t *testing.T, privkey string, event *Event) {
t.Fatalf("event.Sign: %v", err)
}
}
func TestIDCheck(t *testing.T) {
for i := 0; i < 1000; i++ {
evt := Event{
CreatedAt: Timestamp(rand.Int64N(9999999)),
Content: fmt.Sprintf("hello %d", i),
Tags: Tags{},
}
evt.Sign(GeneratePrivateKey())
require.True(t, evt.CheckID())
evt.Content += "!"
require.False(t, evt.CheckID())
}
}
func BenchmarkIDCheck(b *testing.B) {
evt := Event{
CreatedAt: Timestamp(rand.Int64N(9999999)),
Content: fmt.Sprintf("hello"),
Tags: Tags{},
}
evt.Sign(GeneratePrivateKey())
b.Run("naïve", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = evt.GetID() == evt.ID
}
})
b.Run("big brain", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = evt.CheckID()
}
})
}