git.gammaspectra.live/P2Pool/consensus@v0.0.0-20240403173234-a039820b20c9/p2pool/sidechain/cache.go (about) 1 package sidechain 2 3 import ( 4 "encoding/binary" 5 "git.gammaspectra.live/P2Pool/consensus/monero/address" 6 "git.gammaspectra.live/P2Pool/consensus/monero/crypto" 7 "git.gammaspectra.live/P2Pool/consensus/types" 8 "git.gammaspectra.live/P2Pool/consensus/utils" 9 "git.gammaspectra.live/P2Pool/edwards25519" 10 "git.gammaspectra.live/P2Pool/sha3" 11 ) 12 13 type deterministicTransactionCacheKey [crypto.PublicKeySize + types.HashSize]byte 14 type ephemeralPublicKeyCacheKey [crypto.PrivateKeySize + crypto.PublicKeySize*2 + 8]byte 15 type derivationCacheKey [crypto.PrivateKeySize + crypto.PublicKeySize]byte 16 17 type ephemeralPublicKeyWithViewTag struct { 18 PublicKey crypto.PublicKeyBytes 19 ViewTag uint8 20 } 21 22 type DerivationCacheInterface interface { 23 GetEphemeralPublicKey(a *address.PackedAddress, txKeySlice crypto.PrivateKeySlice, txKeyScalar *crypto.PrivateKeyScalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) 24 GetDeterministicTransactionKey(seed types.Hash, prevId types.Hash) *crypto.KeyPair 25 } 26 27 type DerivationCache struct { 28 deterministicKeyCache utils.Cache[deterministicTransactionCacheKey, *crypto.KeyPair] 29 derivationCache utils.Cache[derivationCacheKey, crypto.PublicKeyBytes] 30 ephemeralPublicKeyCache utils.Cache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag] 31 pubKeyToPointCache utils.Cache[crypto.PublicKeyBytes, *edwards25519.Point] 32 } 33 34 func NewDerivationLRUCache() *DerivationCache { 35 d := &DerivationCache{ 36 deterministicKeyCache: utils.NewLRUCache[deterministicTransactionCacheKey, *crypto.KeyPair](32), 37 ephemeralPublicKeyCache: utils.NewLRUCache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag](2000), 38 derivationCache: utils.NewLRUCache[derivationCacheKey, crypto.PublicKeyBytes](2000), 39 pubKeyToPointCache: utils.NewLRUCache[crypto.PublicKeyBytes, *edwards25519.Point](2000), 40 } 41 return d 42 } 43 44 func NewDerivationMapCache() *DerivationCache { 45 d := &DerivationCache{ 46 deterministicKeyCache: utils.NewMapCache[deterministicTransactionCacheKey, *crypto.KeyPair](32), 47 ephemeralPublicKeyCache: utils.NewMapCache[ephemeralPublicKeyCacheKey, ephemeralPublicKeyWithViewTag](2000), 48 derivationCache: utils.NewMapCache[derivationCacheKey, crypto.PublicKeyBytes](2000), 49 pubKeyToPointCache: utils.NewMapCache[crypto.PublicKeyBytes, *edwards25519.Point](2000), 50 } 51 return d 52 } 53 54 func (d *DerivationCache) Clear() { 55 d.deterministicKeyCache.Clear() 56 d.ephemeralPublicKeyCache.Clear() 57 d.derivationCache.Clear() 58 d.pubKeyToPointCache.Clear() 59 } 60 61 func (d *DerivationCache) GetEphemeralPublicKey(a *address.PackedAddress, txKeySlice crypto.PrivateKeySlice, txKeyScalar *crypto.PrivateKeyScalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) { 62 var key ephemeralPublicKeyCacheKey 63 copy(key[:], txKeySlice) 64 copy(key[crypto.PrivateKeySize:], a.ToPackedAddress().Bytes()) 65 binary.LittleEndian.PutUint64(key[crypto.PrivateKeySize+crypto.PublicKeySize*2:], outputIndex) 66 67 if ephemeralPubKey, ok := d.ephemeralPublicKeyCache.Get(key); ok { 68 return ephemeralPubKey.PublicKey, ephemeralPubKey.ViewTag 69 } else { 70 viewPoint := d.getPublicKeyPoint(*a.ViewPublicKey()) 71 spendPoint := d.getPublicKeyPoint(*a.SpendPublicKey()) 72 derivation := d.getDerivation(*a.ViewPublicKey(), txKeySlice, viewPoint, txKeyScalar.Scalar()) 73 pKB, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(spendPoint, derivation, txKeyScalar.Scalar(), outputIndex, hasher) 74 d.ephemeralPublicKeyCache.Set(key, ephemeralPublicKeyWithViewTag{PublicKey: pKB, ViewTag: viewTag}) 75 return pKB, viewTag 76 } 77 } 78 79 func (d *DerivationCache) GetDeterministicTransactionKey(seed types.Hash, prevId types.Hash) *crypto.KeyPair { 80 var key deterministicTransactionCacheKey 81 copy(key[:], seed[:]) 82 copy(key[types.HashSize:], prevId[:]) 83 84 if kp, ok := d.deterministicKeyCache.Get(key); ok { 85 return kp 86 } else { 87 priv := address.GetDeterministicTransactionPrivateKey(seed, prevId).AsBytes() 88 pub := priv.PublicKey().AsBytes() 89 privBytes := priv.AsBytes() 90 kp = &crypto.KeyPair{PrivateKey: &privBytes, PublicKey: &pub} 91 d.deterministicKeyCache.Set(key, kp) 92 return kp 93 } 94 } 95 96 func (d *DerivationCache) getDerivation(viewPublicKeyBytes crypto.PublicKeyBytes, txKeySlice crypto.PrivateKeySlice, viewPublicKeyPoint *edwards25519.Point, txKey *edwards25519.Scalar) crypto.PublicKeyBytes { 97 var key derivationCacheKey 98 copy(key[:], viewPublicKeyBytes[:]) 99 copy(key[crypto.PublicKeySize:], txKeySlice[:]) 100 101 if derivation, ok := d.derivationCache.Get(key); ok { 102 return derivation 103 } else { 104 derivation = address.GetDerivationNoAllocate(viewPublicKeyPoint, txKey) 105 d.derivationCache.Set(key, derivation) 106 return derivation 107 } 108 } 109 110 func (d *DerivationCache) getPublicKeyPoint(publicKey crypto.PublicKeyBytes) *edwards25519.Point { 111 if point, ok := d.pubKeyToPointCache.Get(publicKey); ok { 112 return point 113 } else { 114 point = publicKey.AsPoint().Point() 115 d.pubKeyToPointCache.Set(publicKey, point) 116 return point 117 } 118 }