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  }