consensus/p2pool/sidechain/cache.go

119 lines
4.9 KiB
Go

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"
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
"git.gammaspectra.live/P2Pool/sha3"
)
type deterministicTransactionCacheKey [crypto.PublicKeySize + types.HashSize]byte
type ephemeralPublicKeyCacheKey [crypto.PrivateKeySize + crypto.PublicKeySize*2 + 8]byte
type derivationCacheKey [crypto.PrivateKeySize + crypto.PublicKeySize]byte
type ephemeralPublicKeyWithViewTag struct {
PublicKey crypto.PublicKeyBytes
ViewTag uint8
}
type DerivationCacheInterface interface {
GetEphemeralPublicKey(a *address.PackedAddress, txKeySlice crypto.PrivateKeySlice, txKeyScalar *crypto.PrivateKeyScalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8)
GetDeterministicTransactionKey(seed types.Hash, prevId types.Hash) *crypto.KeyPair
}
type DerivationCache struct {
deterministicKeyCache utils.Cache[deterministicTransactionCacheKey, *crypto.KeyPair]
derivationCache utils.Cache[derivationCacheKey, crypto.PublicKeyBytes]
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),
derivationCache: utils.NewLRUCache[derivationCacheKey, crypto.PublicKeyBytes](2000),
pubKeyToPointCache: utils.NewLRUCache[crypto.PublicKeyBytes, *edwards25519.Point](2000),
}
return d
}
func NewDerivationMapCache() *DerivationCache {
d := &DerivationCache{
deterministicKeyCache: utils.NewMapCache[deterministicTransactionCacheKey, *crypto.KeyPair](32),
ephemeralPublicKeyCache: utils.NewMapCache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag](2000),
derivationCache: utils.NewMapCache[derivationCacheKey, crypto.PublicKeyBytes](2000),
pubKeyToPointCache: utils.NewMapCache[crypto.PublicKeyBytes, *edwards25519.Point](2000),
}
return d
}
func (d *DerivationCache) Clear() {
d.deterministicKeyCache.Clear()
d.ephemeralPublicKeyCache.Clear()
d.derivationCache.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) {
var key ephemeralPublicKeyCacheKey
copy(key[:], txKeySlice)
copy(key[crypto.PrivateKeySize:], a.ToPackedAddress().Bytes())
binary.LittleEndian.PutUint64(key[crypto.PrivateKeySize+crypto.PublicKeySize*2:], outputIndex)
if ephemeralPubKey, ok := d.ephemeralPublicKeyCache.Get(key); ok {
return ephemeralPubKey.PublicKey, ephemeralPubKey.ViewTag
} else {
viewPoint := d.getPublicKeyPoint(*a.ViewPublicKey())
spendPoint := d.getPublicKeyPoint(*a.SpendPublicKey())
derivation := d.getDerivation(*a.ViewPublicKey(), txKeySlice, viewPoint, txKeyScalar.Scalar())
pKB, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(spendPoint, derivation, txKeyScalar.Scalar(), outputIndex, hasher)
d.ephemeralPublicKeyCache.Set(key, ephemeralPublicKeyWithViewTag{PublicKey: pKB, ViewTag: viewTag})
return pKB, viewTag
}
}
func (d *DerivationCache) GetDeterministicTransactionKey(seed types.Hash, prevId types.Hash) *crypto.KeyPair {
var key deterministicTransactionCacheKey
copy(key[:], seed[:])
copy(key[types.HashSize:], prevId[:])
if kp, ok := d.deterministicKeyCache.Get(key); ok {
return kp
} else {
priv := address.GetDeterministicTransactionPrivateKey(seed, prevId).AsBytes()
pub := priv.PublicKey().AsBytes()
privBytes := priv.AsBytes()
kp = &crypto.KeyPair{PrivateKey: &privBytes, PublicKey: &pub}
d.deterministicKeyCache.Set(key, kp)
return kp
}
}
func (d *DerivationCache) getDerivation(viewPublicKeyBytes crypto.PublicKeyBytes, txKeySlice crypto.PrivateKeySlice, viewPublicKeyPoint *edwards25519.Point, txKey *edwards25519.Scalar) crypto.PublicKeyBytes {
var key derivationCacheKey
copy(key[:], viewPublicKeyBytes[:])
copy(key[crypto.PublicKeySize:], txKeySlice[:])
if derivation, ok := d.derivationCache.Get(key); ok {
return derivation
} else {
derivation = address.GetDerivationNoAllocate(viewPublicKeyPoint, txKey)
d.derivationCache.Set(key, derivation)
return derivation
}
}
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
}
}