Speed improvements on partial crypto derivation
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2023-05-23 10:25:10 +02:00
parent 2ad5e1ba38
commit 951b1105ff
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
5 changed files with 45 additions and 14 deletions

View file

@ -66,8 +66,7 @@ func BenchmarkCoinbaseDerivation(b *testing.B) {
}
func BenchmarkCoinbaseDerivationInline(b *testing.B) {
packed := testAddress3.ToPackedAddress()
spendPub, viewPub := packed.SpendPublicKey().AsPoint().Point(), packed.ViewPublicKey().AsPoint().Point()
spendPub, viewPub := testAddress3.SpendPublicKey().AsPoint().Point(), testAddress3.ViewPublicKey().AsPoint().Point()
var i atomic.Uint64
b.RunParallel(func(pb *testing.PB) {
@ -79,9 +78,8 @@ func BenchmarkCoinbaseDerivationInline(b *testing.B) {
}
func BenchmarkCoinbaseDerivationNoAllocate(b *testing.B) {
packed := testAddress3.ToPackedAddress()
spendPub, viewPub := packed.SpendPublicKey().AsPoint().Point(), packed.ViewPublicKey().AsPoint().Point()
spendPub, viewPub := testAddress3.SpendPublicKey().AsPoint().Point(), testAddress3.ViewPublicKey().AsPoint().Point()
txKey := privateKey
@ -90,7 +88,7 @@ func BenchmarkCoinbaseDerivationNoAllocate(b *testing.B) {
hasher := crypto.GetKeccak256Hasher()
defer crypto.PutKeccak256Hasher(hasher)
for pb.Next() {
GetEphemeralPublicKeyAndViewTagNoAllocate(spendPub, viewPub, txKey, i.Add(1), hasher)
GetEphemeralPublicKeyAndViewTagNoAllocate(spendPub, GetDerivationNoAllocate(viewPub, txKey), txKey, i.Add(1), hasher)
}
})
}

View file

@ -42,12 +42,9 @@ func GetEphemeralPublicKeyAndViewTag(a Interface, txKey crypto.PrivateKey, outpu
}
// GetEphemeralPublicKeyAndViewTagNoAllocate Special version of GetEphemeralPublicKeyAndViewTag
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)
derivationSharedData, viewTag := crypto.GetDerivationSharedDataAndViewTagForOutputIndexNoAllocate(crypto.PublicKeyBytes(cofactor.Bytes()), outputIndex, hasher)
func GetEphemeralPublicKeyAndViewTagNoAllocate(spendPublicKeyPoint *edwards25519.Point, derivation crypto.PublicKeyBytes, txKey *edwards25519.Scalar, outputIndex uint64, hasher *sha3.HasherState) (crypto.PublicKeyBytes, uint8) {
var intermediatePublicKey, ephemeralPublicKey edwards25519.Point
derivationSharedData, viewTag := crypto.GetDerivationSharedDataAndViewTagForOutputIndexNoAllocate(derivation, outputIndex, hasher)
intermediatePublicKey.ScalarBaseMult(&derivationSharedData)
ephemeralPublicKey.Add(&intermediatePublicKey, spendPublicKeyPoint)
@ -58,6 +55,15 @@ func GetEphemeralPublicKeyAndViewTagNoAllocate(spendPublicKeyPoint, viewPublicKe
return ephemeralPublicKeyBytes, viewTag
}
// GetDerivationNoAllocate Special version
func GetDerivationNoAllocate(viewPublicKeyPoint *edwards25519.Point, txKey *edwards25519.Scalar) crypto.PublicKeyBytes {
var point, derivation edwards25519.Point
point.UnsafeVarTimeScalarMult(txKey, viewPublicKeyPoint)
derivation.MultByCofactor(&point)
return crypto.PublicKeyBytes(derivation.Bytes())
}
func GetTxProofV2(a Interface, txId types.Hash, txKey crypto.PrivateKey, message string) string {
prefixHash := crypto.Keccak256(txId[:], []byte(message))

View file

@ -12,6 +12,7 @@ import (
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
@ -25,6 +26,7 @@ type DerivationCacheInterface interface {
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]
}
@ -33,6 +35,7 @@ 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
@ -42,7 +45,8 @@ 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),
derivationCache: utils.NewMapCache[derivationCacheKey, crypto.PublicKeyBytes](2000),
pubKeyToPointCache: utils.NewMapCache[crypto.PublicKeyBytes, *edwards25519.Point](2000),
}
return d
}
@ -50,6 +54,7 @@ func NewDerivationMapCache() *DerivationCache {
func (d *DerivationCache) Clear() {
d.deterministicKeyCache.Clear()
d.ephemeralPublicKeyCache.Clear()
d.derivationCache.Clear()
d.pubKeyToPointCache.Clear()
}
@ -62,7 +67,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(d.getPublicKeyPoint(*a.SpendPublicKey()), d.getPublicKeyPoint(*a.ViewPublicKey()), txKeyScalar.Scalar(), outputIndex, hasher)
pKB, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(d.getPublicKeyPoint(*a.SpendPublicKey()), d.getDerivation(*a.ViewPublicKey(), txKeySlice, d.getPublicKeyPoint(*a.ViewPublicKey()), txKeyScalar.Scalar()), txKeyScalar.Scalar(), outputIndex, hasher)
d.ephemeralPublicKeyCache.Set(key, ephemeralPublicKeyWithViewTag{PublicKey: pKB, ViewTag: viewTag})
return pKB, viewTag
}
@ -82,6 +87,20 @@ func (d *DerivationCache) GetDeterministicTransactionKey(seed types.Hash, prevId
}
}
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

View file

@ -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.SpendPublicKey().AsPoint().Point(), a.ViewPublicKey().AsPoint().Point(), txKeyScalar.Scalar(), outputIndex, hasher)
ephemeralPubKey, viewTag := address.GetEphemeralPublicKeyAndViewTagNoAllocate(a.SpendPublicKey().AsPoint().Point(), address.GetDerivationNoAllocate(a.ViewPublicKey().AsPoint().Point(), txKeyScalar.Scalar()), txKeyScalar.Scalar(), outputIndex, hasher)
return ephemeralPubKey.AsBytes(), viewTag
}

View file

@ -147,6 +147,14 @@ func TestSideChainMini(t *testing.T) {
hits, misses = s.DerivationCache().deterministicKeyCache.Stats()
total = hits + misses
log.Printf("Deterministic Key Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
hits, misses = s.DerivationCache().derivationCache.Stats()
total = hits + misses
log.Printf("Derivation Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
hits, misses = s.DerivationCache().pubKeyToPointCache.Stats()
total = hits + misses
log.Printf("PubKeyToPoint Key Cache hits = %d (%.02f%%), misses = %d (%.02f%%), total = %d", hits, (float64(hits)/float64(total))*100, misses, (float64(misses)/float64(total))*100, total)
}
type fakeServer struct {