mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
* v2.1.0.2 * restore tweaks to simlibp2p * fix: nil ref on size calc * fix: panic should induce shutdown from event_distributor * fix: friendlier initialization that requires less manual kickstarting for test/devnets * fix: fewer available shards than provers should choose shard length * fix: update stored worker registry, improve logging for debug mode * fix: shut the fuck up, peer log * qol: log value should be snake cased * fix:non-archive snap sync issues * fix: separate X448/Decaf448 signed keys, add onion key to registry * fix: overflow arithmetic on frame number comparison * fix: worker registration should be idempotent if inputs are same, otherwise permit updated records * fix: remove global prover state from size calculation * fix: divide by zero case * fix: eager prover * fix: broadcast listener default * qol: diagnostic data for peer authenticator * fix: master/worker connectivity issue in sparse networks tight coupling of peer and workers can sometimes interfere if mesh is sparse, so give workers a pseudoidentity but publish messages with the proper peer key * fix: reorder steps of join creation * fix: join verify frame source + ensure domain is properly padded (unnecessary but good for consistency) * fix: add delegate to protobuf <-> reified join conversion * fix: preempt prover from planning with no workers * fix: use the unallocated workers to generate a proof * qol: underflow causes join fail in first ten frames on test/devnets * qol: small logging tweaks for easier log correlation in debug mode * qol: use fisher-yates shuffle to ensure prover allocations are evenly distributed when scores are equal * qol: separate decisional logic on post-enrollment confirmation into consensus engine, proposer, and worker manager where relevant, refactor out scoring * reuse shard descriptors for both join planning and confirm/reject decisions * fix: add missing interface method and amend test blossomsub to use new peer id basis * fix: only check allocations if they exist * fix: pomw mint proof data needs to be hierarchically under global intrinsic domain * staging temporary state under diagnostics * fix: first phase of distributed lock refactoring * fix: compute intrinsic locking * fix: hypergraph intrinsic locking * fix: token intrinsic locking * fix: update execution engines to support new locking model * fix: adjust tests with new execution shape * fix: weave in lock/unlock semantics to liveness provider * fix lock fallthrough, add missing allocation update * qol: additional logging for diagnostics, also testnet/devnet handling for confirmations * fix: establish grace period on halt scenario to permit recovery * fix: support test/devnet defaults for coverage scenarios * fix: nil ref on consensus halts for non-archive nodes * fix: remove unnecessary prefix from prover ref * add test coverage for fork choice behaviors and replay – once passing, blocker (2) is resolved * fix: no fork replay on repeat for non-archive nodes, snap now behaves correctly * rollup of pre-liveness check lock interactions * ahead of tests, get the protobuf/metrics-related changes out so teams can prepare * add test coverage for distributed lock behaviors – once passing, blocker (3) is resolved * fix: blocker (3) * Dev docs improvements (#445) * Make install deps script more robust * Improve testing instructions * Worker node should stop upon OS SIGINT/SIGTERM signal (#447) * move pebble close to Stop() * move deferred Stop() to Start() * add core id to worker stop log message * create done os signal channel and stop worker upon message to it --------- Co-authored-by: Cassandra Heart <7929478+CassOnMars@users.noreply.github.com> --------- Co-authored-by: Daz <daz_the_corgi@proton.me> Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
356 lines
12 KiB
Go
356 lines
12 KiB
Go
//go:build integrationtest
|
|
// +build integrationtest
|
|
|
|
package registration
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"testing"
|
|
|
|
"github.com/cloudflare/circl/sign/ed448"
|
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
"source.quilibrium.com/quilibrium/monorepo/bls48581"
|
|
"source.quilibrium.com/quilibrium/monorepo/bulletproofs"
|
|
"source.quilibrium.com/quilibrium/monorepo/config"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
|
"source.quilibrium.com/quilibrium/monorepo/protobufs"
|
|
"source.quilibrium.com/quilibrium/monorepo/types/crypto"
|
|
)
|
|
|
|
func setupTestKeyStore(t *testing.T) *store.PebbleKeyStore {
|
|
logger, _ := zap.NewDevelopment()
|
|
tempDB := store.NewPebbleDB(logger, &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/store"}, 0)
|
|
return store.NewPebbleKeyStore(tempDB, logger)
|
|
}
|
|
|
|
// Helper functions for generating real keys using concrete constructors
|
|
|
|
func generateRealIdentityKey(t *testing.T) (*protobufs.Ed448PublicKey, ed448.PrivateKey) {
|
|
_, priv, err := ed448.GenerateKey(rand.Reader)
|
|
require.NoError(t, err)
|
|
|
|
pubKey := priv.Public().(ed448.PublicKey)
|
|
return &protobufs.Ed448PublicKey{
|
|
KeyValue: []byte(pubKey),
|
|
}, priv
|
|
}
|
|
|
|
func generateRealProvingKey(t *testing.T, bc *bls48581.Bls48581KeyConstructor) (crypto.Signer, []byte) {
|
|
// Generate a real BLS key with proof of possession
|
|
privKey, pop, err := bc.New()
|
|
require.NoError(t, err)
|
|
|
|
return privKey, pop
|
|
}
|
|
|
|
func generateRealSignedX448Key(t *testing.T, signerPrivKey ed448.PrivateKey, purpose string) *protobufs.SignedX448Key {
|
|
// Generate X448 key
|
|
x448KeyBytes := make([]byte, 57)
|
|
_, err := rand.Read(x448KeyBytes)
|
|
require.NoError(t, err)
|
|
|
|
x448Key := &protobufs.X448PublicKey{
|
|
KeyValue: x448KeyBytes,
|
|
}
|
|
|
|
// Get signer public key
|
|
signerPubKey := signerPrivKey.Public().(ed448.PublicKey)
|
|
|
|
// Calculate parent key address
|
|
addressBI, err := poseidon.HashBytes([]byte(signerPubKey))
|
|
require.NoError(t, err)
|
|
parentKeyAddress := addressBI.FillBytes(make([]byte, 32))
|
|
|
|
// Sign the X448 key
|
|
signature := ed448.Sign(signerPrivKey, x448KeyBytes, "KEY_REGISTRY")
|
|
|
|
return &protobufs.SignedX448Key{
|
|
Key: x448Key,
|
|
ParentKeyAddress: parentKeyAddress,
|
|
Signature: &protobufs.SignedX448Key_Ed448Signature{
|
|
Ed448Signature: &protobufs.Ed448Signature{
|
|
Signature: signature,
|
|
PublicKey: &protobufs.Ed448PublicKey{
|
|
KeyValue: []byte(signerPubKey),
|
|
},
|
|
},
|
|
},
|
|
CreatedAt: 1234567890,
|
|
ExpiresAt: 0,
|
|
KeyPurpose: purpose,
|
|
}
|
|
}
|
|
|
|
// TestLoadExistingKeys tests loading keys from an existing store
|
|
func TestLoadExistingKeys(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
keyStore := setupTestKeyStore(t)
|
|
bc := &bls48581.Bls48581KeyConstructor{}
|
|
dc := &bulletproofs.Decaf448KeyConstructor{}
|
|
bp := &bulletproofs.Decaf448BulletproofProver{}
|
|
keyManager := keys.NewInMemoryKeyManager(bc, dc)
|
|
|
|
// First populate the store with some test data
|
|
txn, err := keyStore.NewTransaction()
|
|
require.NoError(t, err)
|
|
|
|
// Generate real keys for testing
|
|
numKeys := 3
|
|
var testProvingKeys []crypto.Signer
|
|
var testIdentityKeys []*protobufs.Ed448PublicKey
|
|
var testPrivKeys []ed448.PrivateKey
|
|
var testPopSigs [][]byte
|
|
|
|
for i := 0; i < numKeys; i++ {
|
|
// Generate real identity key
|
|
identityKey, privKey := generateRealIdentityKey(t)
|
|
testIdentityKeys = append(testIdentityKeys, identityKey)
|
|
testPrivKeys = append(testPrivKeys, privKey)
|
|
|
|
// Generate real proving key
|
|
provingKey, popsig := generateRealProvingKey(t, bc)
|
|
testProvingKeys = append(testProvingKeys, provingKey)
|
|
testPopSigs = append(testPopSigs, popsig)
|
|
}
|
|
|
|
// Store the keys
|
|
for i, provingKey := range testProvingKeys {
|
|
provingKeyAddressBI, _ := poseidon.HashBytes(provingKey.Public().([]byte))
|
|
provingKeyAddress := provingKeyAddressBI.FillBytes(make([]byte, 32))
|
|
|
|
identityKeyAddressBI, _ := poseidon.HashBytes(testIdentityKeys[i].KeyValue)
|
|
identityKeyAddress := identityKeyAddressBI.FillBytes(make([]byte, 32))
|
|
|
|
// Store proving key
|
|
err := keyStore.PutProvingKey(txn, provingKeyAddress, &protobufs.BLS48581SignatureWithProofOfPossession{
|
|
PublicKey: &protobufs.BLS48581G2PublicKey{
|
|
KeyValue: provingKey.Public().([]byte),
|
|
},
|
|
PopSignature: testPopSigs[i],
|
|
Signature: testPopSigs[i],
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Store identity key
|
|
err = keyStore.PutIdentityKey(txn, identityKeyAddress, testIdentityKeys[i])
|
|
require.NoError(t, err)
|
|
|
|
identitySig := generateTestEd448Signature(testPrivKeys[i], provingKey.Public().([]byte), []byte("KEY_REGISTRY"))
|
|
provingSig, err := provingKey.SignWithDomain(testIdentityKeys[i].KeyValue, []byte("KEY_REGISTRY"))
|
|
require.NoError(t, err)
|
|
// Store cross signatures
|
|
err = keyStore.PutCrossSignature(
|
|
txn,
|
|
identityKeyAddress,
|
|
provingKeyAddress,
|
|
identitySig,
|
|
provingSig,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Store a signed key using the real identity private key
|
|
signedKey := generateRealSignedX448Key(t, testPrivKeys[i], "inbox")
|
|
|
|
signedKeyAddressBI, _ := poseidon.HashBytes(signedKey.Key.KeyValue)
|
|
signedKeyAddress := signedKeyAddressBI.FillBytes(make([]byte, 32))
|
|
|
|
err = keyStore.PutSignedX448Key(txn, signedKeyAddress, signedKey)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
err = txn.Commit()
|
|
require.NoError(t, err)
|
|
|
|
// Create the registry - it should load existing keys
|
|
registry, err := NewCachedSignerRegistry(keyStore, keyManager, bc, bp, logger)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, registry)
|
|
assert.Equal(t, len(testProvingKeys), registry.GetSignerCount())
|
|
}
|
|
|
|
// TestFullWorkflow tests the complete workflow of the registry
|
|
func TestFullWorkflow(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
keyStore := setupTestKeyStore(t)
|
|
bc := &bls48581.Bls48581KeyConstructor{}
|
|
dc := &bulletproofs.Decaf448KeyConstructor{}
|
|
bp := &bulletproofs.Decaf448BulletproofProver{}
|
|
keyManager := keys.NewInMemoryKeyManager(bc, dc)
|
|
|
|
registry, err := NewCachedSignerRegistry(keyStore, keyManager, bc, bp, logger)
|
|
require.NoError(t, err)
|
|
|
|
// Start a transaction
|
|
txn, err := keyStore.NewTransaction()
|
|
require.NoError(t, err)
|
|
|
|
// Step 1: Put an identity key
|
|
identityKey, identityPrivKey := generateRealIdentityKey(t)
|
|
identityKeyAddressBI, _ := poseidon.HashBytes(identityKey.KeyValue)
|
|
identityKeyAddress := identityKeyAddressBI.FillBytes(make([]byte, 32))
|
|
|
|
err = registry.PutIdentityKey(txn, identityKeyAddress, identityKey)
|
|
require.NoError(t, err)
|
|
|
|
// Step 2: Put a proving key
|
|
provingKey, popSig := generateRealProvingKey(t, bc)
|
|
provingKeyAddressBI, _ := poseidon.HashBytes(provingKey.Public().([]byte))
|
|
provingKeyAddress := provingKeyAddressBI.FillBytes(make([]byte, 32))
|
|
|
|
err = registry.PutProvingKey(txn, provingKeyAddress, &protobufs.BLS48581SignatureWithProofOfPossession{
|
|
PublicKey: &protobufs.BLS48581G2PublicKey{
|
|
KeyValue: provingKey.Public().([]byte),
|
|
},
|
|
Signature: popSig,
|
|
PopSignature: popSig,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Step 3: Put cross signatures
|
|
identitySig := generateTestEd448Signature(identityPrivKey, provingKey.Public().([]byte), []byte("KEY_REGISTRY"))
|
|
provingSig, err := provingKey.SignWithDomain(identityKey.KeyValue, []byte("KEY_REGISTRY"))
|
|
require.NoError(t, err)
|
|
|
|
err = registry.PutCrossSignature(txn, identityKeyAddress, provingKeyAddress, identitySig, provingSig)
|
|
require.NoError(t, err)
|
|
|
|
// Step 4: Put a signed key
|
|
signedKey := generateRealSignedX448Key(t, identityPrivKey, "inbox")
|
|
signedKeyAddressBI, _ := poseidon.HashBytes(signedKey.Key.KeyValue)
|
|
signedKeyAddress := signedKeyAddressBI.FillBytes(make([]byte, 32))
|
|
|
|
err = keyStore.PutSignedX448Key(txn, signedKeyAddress, signedKey)
|
|
require.NoError(t, err)
|
|
|
|
// Commit the transaction
|
|
err = txn.Commit()
|
|
require.NoError(t, err)
|
|
|
|
// Step 5: Get the key registry
|
|
result, err := registry.GetKeyRegistry(identityKeyAddress)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, identityKey.KeyValue, result.IdentityKey.KeyValue)
|
|
assert.Equal(t, provingKey.Public().([]byte), result.ProverKey.KeyValue)
|
|
assert.Len(t, result.KeysByPurpose, 1)
|
|
assert.Contains(t, result.KeysByPurpose, "inbox")
|
|
}
|
|
|
|
// TestValidationIntegration tests the validation flow
|
|
func TestValidationIntegration(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
keyStore := setupTestKeyStore(t)
|
|
bc := &bls48581.Bls48581KeyConstructor{}
|
|
dc := &bulletproofs.Decaf448KeyConstructor{}
|
|
bp := &bulletproofs.Decaf448BulletproofProver{}
|
|
keyManager := keys.NewInMemoryKeyManager(bc, dc)
|
|
|
|
registry, err := NewCachedSignerRegistry(keyStore, keyManager, bc, bp, logger)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Invalid proving key rejected", func(t *testing.T) {
|
|
// Create an invalid proving key (nil)
|
|
err := registry.ValidateProvingKey(nil)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "validate proving key")
|
|
})
|
|
|
|
t.Run("Invalid proving key signature rejected", func(t *testing.T) {
|
|
// Create a proving key with invalid proof of possession
|
|
// We'll create one with random bytes that won't pass BLS verification
|
|
provingKey := &protobufs.BLS48581SignatureWithProofOfPossession{
|
|
PublicKey: &protobufs.BLS48581G2PublicKey{
|
|
KeyValue: make([]byte, 585), // Random bytes
|
|
},
|
|
Signature: make([]byte, 74), // Random bytes
|
|
PopSignature: make([]byte, 74), // Random bytes
|
|
}
|
|
rand.Read(provingKey.PublicKey.KeyValue)
|
|
rand.Read(provingKey.Signature)
|
|
rand.Read(provingKey.PopSignature)
|
|
|
|
txn, err := keyStore.NewTransaction()
|
|
require.NoError(t, err)
|
|
|
|
address := generateTestAddress()
|
|
err = registry.PutProvingKey(txn, address, provingKey)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid signature")
|
|
|
|
_ = txn.Abort()
|
|
})
|
|
|
|
t.Run("Invalid signed key rejected", func(t *testing.T) {
|
|
// Create a signed key with mismatched parent key address
|
|
// Generate a random ed448 key pair
|
|
_, randomPrivKey, err := ed448.GenerateKey(rand.Reader)
|
|
require.NoError(t, err)
|
|
|
|
// Create a signed key with this key
|
|
signedKey := generateRealSignedX448Key(t, randomPrivKey, "device")
|
|
|
|
// But set a different parent key address that doesn't match
|
|
randomAddress := generateTestAddress()
|
|
signedKey.ParentKeyAddress = randomAddress
|
|
|
|
err = registry.ValidateSignedX448Key(signedKey)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "validate signed key")
|
|
})
|
|
}
|
|
|
|
// TestCacheManagement tests cache management operations
|
|
func TestCacheManagement(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
keyStore := setupTestKeyStore(t)
|
|
bc := &bls48581.Bls48581KeyConstructor{}
|
|
dc := &bulletproofs.Decaf448KeyConstructor{}
|
|
bp := &bulletproofs.Decaf448BulletproofProver{}
|
|
keyManager := keys.NewInMemoryKeyManager(bc, dc)
|
|
|
|
registry, err := NewCachedSignerRegistry(keyStore, keyManager, bc, bp, logger)
|
|
require.NoError(t, err)
|
|
|
|
// Initially empty
|
|
assert.Equal(t, 0, registry.GetSignerCount())
|
|
|
|
// Clear cache (should be no-op when empty)
|
|
registry.ClearCache()
|
|
assert.Equal(t, 0, registry.GetSignerCount())
|
|
|
|
// Get all signers when empty
|
|
signers := registry.GetAllSigners()
|
|
assert.Len(t, signers, 0)
|
|
}
|
|
|
|
// BenchmarkCachedSignerRegistry benchmarks various operations
|
|
func BenchmarkCachedSignerRegistry(b *testing.B) {
|
|
logger := zap.NewNop()
|
|
tempDB := store.NewPebbleDB(logger, &config.DBConfig{InMemoryDONOTUSE: true, Path: ".test/store"}, 0)
|
|
keyStore := store.NewPebbleKeyStore(tempDB, logger)
|
|
bc := &bls48581.Bls48581KeyConstructor{}
|
|
dc := &bulletproofs.Decaf448KeyConstructor{}
|
|
bp := &bulletproofs.Decaf448BulletproofProver{}
|
|
keyManager := keys.NewInMemoryKeyManager(bc, dc)
|
|
|
|
registry, _ := NewCachedSignerRegistry(keyStore, keyManager, bc, bp, logger)
|
|
|
|
b.Run("GetSignerCount", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = registry.GetSignerCount()
|
|
}
|
|
})
|
|
|
|
b.Run("GetAllSigners", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = registry.GetAllSigners()
|
|
}
|
|
})
|
|
}
|