diff --git a/monero/address/address_test.go b/monero/address/address_test.go index 98cf684..aa50001 100644 --- a/monero/address/address_test.go +++ b/monero/address/address_test.go @@ -60,7 +60,7 @@ func BenchmarkCoinbaseDerivation(b *testing.B) { var i atomic.Uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - GetEphemeralPublicKeyAndViewTag(&packed, txKey, i.Load()) + GetEphemeralPublicKeyAndViewTag(&packed, txKey, i.Add(1)) } }) } @@ -73,7 +73,7 @@ func BenchmarkCoinbaseDerivationInline(b *testing.B) { b.RunParallel(func(pb *testing.PB) { p := new(edwards25519.Point) for pb.Next() { - getEphemeralPublicKeyInline(spendPub, viewPub, privateKey, i.Load(), p) + getEphemeralPublicKeyInline(spendPub, viewPub, privateKey, i.Add(1), p) } }) } @@ -81,14 +81,16 @@ func BenchmarkCoinbaseDerivationInline(b *testing.B) { func BenchmarkCoinbaseDerivationNoAllocate(b *testing.B) { packed := testAddress3.ToPackedAddress() - txKey := (*crypto.PrivateKeyScalar)(privateKey) + spendPub, viewPub := packed.SpendPublicKey().AsPoint().Point(), packed.ViewPublicKey().AsPoint().Point() + + txKey := privateKey var i atomic.Uint64 b.RunParallel(func(pb *testing.PB) { hasher := crypto.GetKeccak256Hasher() defer crypto.PutKeccak256Hasher(hasher) for pb.Next() { - GetEphemeralPublicKeyAndViewTagNoAllocate(&packed, txKey, i.Load(), hasher) + GetEphemeralPublicKeyAndViewTagNoAllocate(spendPub, viewPub, txKey, i.Add(1), hasher) } }) } diff --git a/monero/address/crypto.go b/monero/address/crypto.go index 4da4ab6..92f06e0 100644 --- a/monero/address/crypto.go +++ b/monero/address/crypto.go @@ -42,18 +42,15 @@ func GetEphemeralPublicKeyAndViewTag(a Interface, txKey crypto.PrivateKey, outpu } // GetEphemeralPublicKeyAndViewTagNoAllocate Special version of GetEphemeralPublicKeyAndViewTag -func GetEphemeralPublicKeyAndViewTagNoAllocate(a *PackedAddress, txKey *crypto.PrivateKeyScalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) { - scalar := txKey.Scalar() - var spendPublicKeyPoint, viewPublicKeyPoint, point, cofactor, intermediatePublicKey, ephemeralPublicKey edwards25519.Point - _, _ = spendPublicKeyPoint.SetBytes((*a)[0][:]) - _, _ = viewPublicKeyPoint.SetBytes((*a)[1][:]) - point.UnsafeVarTimeScalarMult(scalar, &viewPublicKeyPoint) +func GetEphemeralPublicKeyAndViewTagNoAllocate(spendPublicKeyPoint, viewPublicKeyPoint *edwards25519.Point, txKey *edwards25519.Scalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) { + var point, cofactor, intermediatePublicKey, ephemeralPublicKey edwards25519.Point + point.UnsafeVarTimeScalarMult(txKey, viewPublicKeyPoint) cofactor.MultByCofactor(&point) - pK, viewTag := crypto.GetDerivationSharedDataAndViewTagForOutputIndexNoAllocate(crypto.PublicKeyBytes(cofactor.Bytes()), outputIndex, hasher) + derivationSharedData, viewTag := crypto.GetDerivationSharedDataAndViewTagForOutputIndexNoAllocate(crypto.PublicKeyBytes(cofactor.Bytes()), outputIndex, hasher) - intermediatePublicKey.ScalarBaseMult(&pK) - ephemeralPublicKey.Add(&intermediatePublicKey, &spendPublicKeyPoint) + intermediatePublicKey.ScalarBaseMult(&derivationSharedData) + ephemeralPublicKey.Add(&intermediatePublicKey, spendPublicKeyPoint) var ephemeralPublicKeyBytes crypto.PublicKeyBytes copy(ephemeralPublicKeyBytes[:], ephemeralPublicKey.Bytes()) diff --git a/p2pool/sidechain/cache.go b/p2pool/sidechain/cache.go index 934a1b8..5b6885e 100644 --- a/p2pool/sidechain/cache.go +++ b/p2pool/sidechain/cache.go @@ -2,6 +2,7 @@ package sidechain import ( "encoding/binary" + "git.gammaspectra.live/P2Pool/edwards25519" "git.gammaspectra.live/P2Pool/p2pool-observer/monero/address" "git.gammaspectra.live/P2Pool/p2pool-observer/monero/crypto" "git.gammaspectra.live/P2Pool/p2pool-observer/types" @@ -25,12 +26,14 @@ type DerivationCacheInterface interface { type DerivationCache struct { deterministicKeyCache utils.Cache[deterministicTransactionCacheKey, *crypto.KeyPair] ephemeralPublicKeyCache utils.Cache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag] + pubKeyToPointCache utils.Cache[crypto.PublicKeyBytes, *edwards25519.Point] } func NewDerivationLRUCache() *DerivationCache { d := &DerivationCache{ deterministicKeyCache: utils.NewLRUCache[deterministicTransactionCacheKey, *crypto.KeyPair](32), ephemeralPublicKeyCache: utils.NewLRUCache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag](2000), + pubKeyToPointCache: utils.NewLRUCache[crypto.PublicKeyBytes, *edwards25519.Point](2000), } return d } @@ -39,6 +42,7 @@ func NewDerivationMapCache() *DerivationCache { d := &DerivationCache{ deterministicKeyCache: utils.NewMapCache[deterministicTransactionCacheKey, *crypto.KeyPair](32), ephemeralPublicKeyCache: utils.NewMapCache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag](2000), + pubKeyToPointCache: utils.NewLRUCache[crypto.PublicKeyBytes, *edwards25519.Point](2000), } return d } @@ -46,6 +50,7 @@ func NewDerivationMapCache() *DerivationCache { func (d *DerivationCache) Clear() { d.deterministicKeyCache.Clear() d.ephemeralPublicKeyCache.Clear() + d.pubKeyToPointCache.Clear() } func (d *DerivationCache) GetEphemeralPublicKey(a *address.PackedAddress, txKeySlice crypto.PrivateKeySlice, txKeyScalar *crypto.PrivateKeyScalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) { @@ -57,7 +62,7 @@ func (d *DerivationCache) GetEphemeralPublicKey(a *address.PackedAddress, txKeyS if ephemeralPubKey, ok := d.ephemeralPublicKeyCache.Get(key); ok { return ephemeralPubKey.PublicKey, ephemeralPubKey.ViewTag } else { - pKB, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(a, txKeyScalar, outputIndex, hasher) + pKB, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(d.getPublicKeyPoint(*a.SpendPublicKey()), d.getPublicKeyPoint(*a.ViewPublicKey()), txKeyScalar.Scalar(), outputIndex, hasher) d.ephemeralPublicKeyCache.Set(key, ephemeralPublicKeyWithViewTag{PublicKey: pKB, ViewTag: viewTag}) return pKB, viewTag } @@ -76,3 +81,13 @@ func (d *DerivationCache) GetDeterministicTransactionKey(seed types.Hash, prevId return data } } + +func (d *DerivationCache) getPublicKeyPoint(publicKey crypto.PublicKeyBytes) *edwards25519.Point { + if point, ok := d.pubKeyToPointCache.Get(publicKey); ok { + return point + } else { + point = publicKey.AsPoint().Point() + d.pubKeyToPointCache.Set(publicKey, point) + return point + } +} diff --git a/p2pool/sidechain/nilcache.go b/p2pool/sidechain/nilcache.go index 64f83fc..c62962e 100644 --- a/p2pool/sidechain/nilcache.go +++ b/p2pool/sidechain/nilcache.go @@ -15,7 +15,7 @@ func (d *NilDerivationCache) Clear() { } func (d *NilDerivationCache) GetEphemeralPublicKey(a *address.PackedAddress, _ crypto.PrivateKeySlice, txKeyScalar *crypto.PrivateKeyScalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) { - ephemeralPubKey, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(a, txKeyScalar, outputIndex, hasher) + ephemeralPubKey, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(a.SpendPublicKey().AsPoint().Point(), a.ViewPublicKey().AsPoint().Point(), txKeyScalar.Scalar(), outputIndex, hasher) return ephemeralPubKey.AsBytes(), viewTag } diff --git a/p2pool/sidechain/utils.go b/p2pool/sidechain/utils.go index 65aa1db..d27b388 100644 --- a/p2pool/sidechain/utils.go +++ b/p2pool/sidechain/utils.go @@ -14,8 +14,8 @@ import ( "git.gammaspectra.live/P2Pool/sha3" "golang.org/x/exp/slices" "log" - "lukechampine.com/uint128" "math" + "math/bits" ) type GetByMainIdFunc func(h types.Hash) *PoolBlock @@ -256,7 +256,7 @@ func GetShares(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.Ge // ShuffleShares Sorts shares according to consensus parameters. Requires pre-sorted shares based on address func ShuffleShares[T any](shares []T, shareVersion ShareVersion, privateKeySeed types.Hash) { - n := len(shares) + n := uint64(len(shares)) if shareVersion > ShareVersion_V1 && n > 1 { h := crypto.PooledKeccak256(privateKeySeed[:]) seed := binary.LittleEndian.Uint64(h[:]) @@ -265,9 +265,9 @@ func ShuffleShares[T any](shares []T, shareVersion ShareVersion, privateKeySeed seed = 1 } - for i := 0; i < (n - 1); i++ { + for i := uint64(0); i < (n - 1); i++ { seed = utils.XorShift64Star(seed) - k := int(uint128.From64(seed).Mul64(uint64(n - i)).Hi) + k, _ := bits.Mul64(seed, n-i) //swap shares[i], shares[i+k] = shares[i+k], shares[i] } diff --git a/utils/xorshift64star.go b/utils/xorshift64star.go index 9f94318..c21a26a 100644 --- a/utils/xorshift64star.go +++ b/utils/xorshift64star.go @@ -1,5 +1,7 @@ package utils +// XorShift64Star Implementation of xorshift* https://en.wikipedia.org/wiki/Xorshift#xorshift* +// x must be initialized to a non-zero value func XorShift64Star(x uint64) uint64 { x ^= x >> 12 x ^= x << 25