mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-26 00:25:17 +00:00
v1.2.4 (#43)
This commit is contained in:
parent
1a1ef542d0
commit
0cd6b41f5d
@ -23,7 +23,7 @@ import (
|
|||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony/application"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
||||||
@ -886,11 +886,11 @@ func logoVersion(width int) string {
|
|||||||
out += " ####################################### ########\n"
|
out += " ####################################### ########\n"
|
||||||
out += " ############################# ##\n"
|
out += " ############################# ##\n"
|
||||||
out += " \n"
|
out += " \n"
|
||||||
out += " Quilibrium Node - v1.2.3 – Dawn\n"
|
out += " Quilibrium Node - v1.2.4 – Dawn\n"
|
||||||
out += " \n"
|
out += " \n"
|
||||||
out += " DB Console\n"
|
out += " DB Console\n"
|
||||||
} else {
|
} else {
|
||||||
out = "Quilibrium Node - v1.2.3 – Dawn - DB Console\n"
|
out = "Quilibrium Node - v1.2.4 – Dawn - DB Console\n"
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
|
@ -9,7 +9,9 @@ import (
|
|||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus/master"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/master"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
@ -54,6 +56,11 @@ var pubSubSet = wire.NewSet(
|
|||||||
|
|
||||||
var engineSet = wire.NewSet(
|
var engineSet = wire.NewSet(
|
||||||
wire.FieldsOf(new(*config.Config), "Engine"),
|
wire.FieldsOf(new(*config.Config), "Engine"),
|
||||||
|
crypto.NewWesolowskiFrameProver,
|
||||||
|
wire.Bind(new(crypto.FrameProver), new(*crypto.WesolowskiFrameProver)),
|
||||||
|
crypto.NewKZGInclusionProver,
|
||||||
|
wire.Bind(new(crypto.InclusionProver), new(*crypto.KZGInclusionProver)),
|
||||||
|
time.NewMasterTimeReel,
|
||||||
ceremony.NewCeremonyExecutionEngine,
|
ceremony.NewCeremonyExecutionEngine,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ import (
|
|||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus/master"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/master"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
@ -30,9 +32,12 @@ func NewNode(configConfig *config.Config) (*Node, error) {
|
|||||||
p2PConfig := configConfig.P2P
|
p2PConfig := configConfig.P2P
|
||||||
blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger)
|
blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger)
|
||||||
engineConfig := configConfig.Engine
|
engineConfig := configConfig.Engine
|
||||||
|
wesolowskiFrameProver := crypto.NewWesolowskiFrameProver(zapLogger)
|
||||||
|
kzgInclusionProver := crypto.NewKZGInclusionProver(zapLogger)
|
||||||
|
masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, wesolowskiFrameProver)
|
||||||
pebbleKeyStore := store.NewPebbleKeyStore(pebbleDB, zapLogger)
|
pebbleKeyStore := store.NewPebbleKeyStore(pebbleDB, zapLogger)
|
||||||
ceremonyExecutionEngine := ceremony.NewCeremonyExecutionEngine(zapLogger, engineConfig, fileKeyManager, blossomSub, pebbleClockStore, pebbleKeyStore)
|
ceremonyExecutionEngine := ceremony.NewCeremonyExecutionEngine(zapLogger, engineConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, masterTimeReel, pebbleKeyStore)
|
||||||
masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub)
|
masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, wesolowskiFrameProver, masterTimeReel)
|
||||||
node, err := newNode(zapLogger, pebbleClockStore, fileKeyManager, blossomSub, ceremonyExecutionEngine, masterClockConsensusEngine)
|
node, err := newNode(zapLogger, pebbleClockStore, fileKeyManager, blossomSub, ceremonyExecutionEngine, masterClockConsensusEngine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -77,7 +82,7 @@ var storeSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "DB"), store.NewPe
|
|||||||
|
|
||||||
var pubSubSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "P2P"), p2p.NewBlossomSub, wire.Bind(new(p2p.PubSub), new(*p2p.BlossomSub)))
|
var pubSubSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "P2P"), p2p.NewBlossomSub, wire.Bind(new(p2p.PubSub), new(*p2p.BlossomSub)))
|
||||||
|
|
||||||
var engineSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Engine"), ceremony.NewCeremonyExecutionEngine)
|
var engineSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Engine"), crypto.NewWesolowskiFrameProver, wire.Bind(new(crypto.FrameProver), new(*crypto.WesolowskiFrameProver)), crypto.NewKZGInclusionProver, wire.Bind(new(crypto.InclusionProver), new(*crypto.KZGInclusionProver)), time.NewMasterTimeReel, ceremony.NewCeremonyExecutionEngine)
|
||||||
|
|
||||||
var consensusSet = wire.NewSet(master.NewMasterClockConsensusEngine, wire.Bind(
|
var consensusSet = wire.NewSet(master.NewMasterClockConsensusEngine, wire.Bind(
|
||||||
new(consensus.ConsensusEngine),
|
new(consensus.ConsensusEngine),
|
||||||
|
@ -11,17 +11,13 @@ import (
|
|||||||
"github.com/libp2p/go-libp2p/core/peer"
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) handleMessage(
|
func (e *CeremonyDataClockConsensusEngine) handleMessage(
|
||||||
@ -304,17 +300,8 @@ func (e *CeremonyDataClockConsensusEngine) handleClockFrameData(
|
|||||||
return errors.Wrap(err, "handle clock frame data")
|
return errors.Wrap(err, "handle clock frame data")
|
||||||
}
|
}
|
||||||
|
|
||||||
earliestFrame, _, count := e.frameProverTrie.Get(addr.Bytes())
|
prover := e.frameProverTrie.FindNearest(addr.Bytes())
|
||||||
_, latestFrame, _ := e.frameSeenProverTrie.Get(addr.Bytes())
|
if !bytes.Equal(prover.External.Key, addr.Bytes()) {
|
||||||
if !isSync && frame.FrameNumber == latestFrame {
|
|
||||||
e.logger.Info(
|
|
||||||
"already received frame from address",
|
|
||||||
zap.Binary("address", address),
|
|
||||||
zap.Binary("filter", frame.Filter),
|
|
||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
} else if frame.FrameNumber <= earliestFrame || count == 0 {
|
|
||||||
e.logger.Info(
|
e.logger.Info(
|
||||||
"prover not in trie at frame, address may be in fork",
|
"prover not in trie at frame, address may be in fork",
|
||||||
zap.Binary("address", address),
|
zap.Binary("address", address),
|
||||||
@ -332,167 +319,14 @@ func (e *CeremonyDataClockConsensusEngine) handleClockFrameData(
|
|||||||
zap.Int("proof_count", len(frame.AggregateProofs)),
|
zap.Int("proof_count", len(frame.AggregateProofs)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := frame.VerifyDataClockFrame(); err != nil {
|
if err := e.frameProver.VerifyDataClockFrame(frame); err != nil {
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
e.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
return errors.Wrap(err, "handle clock frame data")
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregateCommitments := []curves.PairingPoint{}
|
if err := e.inclusionProver.VerifyFrame(frame); err != nil {
|
||||||
for i := 0; i < (len(frame.Input)-516)/74; i++ {
|
e.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
return errors.Wrap(err, "handle clock frame data")
|
||||||
frame.Input[516+(i*74) : 516+(i*74)+74],
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
aggregateCommitments = append(aggregateCommitments, c.(curves.PairingPoint))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, proof := range frame.AggregateProofs {
|
|
||||||
aggregatePoly := [][]curves.PairingScalar{}
|
|
||||||
commitments := []curves.PairingPoint{}
|
|
||||||
|
|
||||||
for _, commit := range proof.GetInclusionCommitments() {
|
|
||||||
switch commit.TypeUrl {
|
|
||||||
case protobufs.IntrinsicExecutionOutputType:
|
|
||||||
e.logger.Debug("confirming inclusion in aggregate")
|
|
||||||
digest := sha3.NewShake256()
|
|
||||||
_, err := digest.Write(commit.Data)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error converting key bundle to polynomial",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
expand := make([]byte, 1024)
|
|
||||||
_, err = digest.Read(expand)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error converting key bundle to polynomial",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
poly, err := e.prover.BytesToPolynomial(expand)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error converting key bundle to polynomial",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
evalPoly, err := qcrypto.FFT(
|
|
||||||
poly,
|
|
||||||
*curves.BLS48581(
|
|
||||||
curves.BLS48581G1().NewGeneratorPoint(),
|
|
||||||
),
|
|
||||||
16,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error performing fast fourier transform on key bundle",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
e.logger.Debug(
|
|
||||||
"created fft of polynomial",
|
|
||||||
zap.Int("poly_size", len(evalPoly)),
|
|
||||||
)
|
|
||||||
|
|
||||||
aggregatePoly = append(aggregatePoly, evalPoly)
|
|
||||||
|
|
||||||
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
|
||||||
commit.Commitment,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
commitments = append(commitments, c.(curves.PairingPoint))
|
|
||||||
default:
|
|
||||||
e.logger.Debug("confirming inclusion in aggregate")
|
|
||||||
poly, err := e.prover.BytesToPolynomial(commit.Data)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error converting key bundle to polynomial",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 128-len(poly); i++ {
|
|
||||||
poly = append(
|
|
||||||
poly,
|
|
||||||
curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
evalPoly, err := qcrypto.FFT(
|
|
||||||
poly,
|
|
||||||
*curves.BLS48581(
|
|
||||||
curves.BLS48581G1().NewGeneratorPoint(),
|
|
||||||
),
|
|
||||||
128,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error performing fast fourier transform on key bundle",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
e.logger.Debug(
|
|
||||||
"created fft of polynomial",
|
|
||||||
zap.Int("poly_size", len(evalPoly)),
|
|
||||||
)
|
|
||||||
|
|
||||||
aggregatePoly = append(aggregatePoly, evalPoly)
|
|
||||||
|
|
||||||
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
|
||||||
commit.Commitment,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
commitments = append(commitments, c.(curves.PairingPoint))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
|
||||||
proof.Proof,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := e.prover.VerifyAggregateProof(
|
|
||||||
aggregatePoly,
|
|
||||||
commitments,
|
|
||||||
aggregateCommitments[i],
|
|
||||||
p.(curves.PairingPoint),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !result {
|
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid proof"),
|
|
||||||
"handle clock frame data",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.logger.Info(
|
e.logger.Info(
|
||||||
@ -501,102 +335,23 @@ func (e *CeremonyDataClockConsensusEngine) handleClockFrameData(
|
|||||||
zap.Binary("filter", frame.Filter),
|
zap.Binary("filter", frame.Filter),
|
||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
zap.Uint64("frame_number", frame.FrameNumber),
|
||||||
)
|
)
|
||||||
masterFrame, err := e.clockStore.GetMasterClockFrame(
|
|
||||||
[]byte{
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
},
|
|
||||||
frame.FrameNumber-1,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Info("received frame with no known master, needs sync")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
discriminator, err := masterFrame.GetSelector()
|
e.dataTimeReel.Insert(frame)
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
parentSelector, distance, selector, err :=
|
|
||||||
frame.GetParentSelectorAndDistance(discriminator)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := e.clockStore.GetParentDataClockFrame(
|
|
||||||
frame.Filter,
|
|
||||||
frame.FrameNumber-1,
|
|
||||||
frame.ParentSelector,
|
|
||||||
); errors.Is(err, store.ErrNotFound) {
|
|
||||||
// If this is a frame number higher than what we're already caught up to,
|
|
||||||
// push a request to fill the gap, unless we're syncing or it's in step,
|
|
||||||
// then just lazily seek.
|
|
||||||
from := e.frame.FrameNumber
|
|
||||||
if from >= frame.FrameNumber-1 {
|
|
||||||
from = frame.FrameNumber - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := e.publishMessage(e.filter, &protobufs.ClockFramesRequest{
|
|
||||||
Filter: e.filter,
|
|
||||||
FromFrameNumber: from,
|
|
||||||
ToFrameNumber: frame.FrameNumber,
|
|
||||||
}); err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"could not publish clock frame parent request, skipping",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
txn, err := e.clockStore.NewTransaction()
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not save candidate clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := e.clockStore.PutCandidateDataClockFrame(
|
|
||||||
parentSelector.FillBytes(make([]byte, 32)),
|
|
||||||
distance.FillBytes(make([]byte, 32)),
|
|
||||||
selector.FillBytes(make([]byte, 32)),
|
|
||||||
frame,
|
|
||||||
txn,
|
|
||||||
); err != nil {
|
|
||||||
e.logger.Error("could not save candidate clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := txn.Commit(); err != nil {
|
|
||||||
e.logger.Error("could not save candidate clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.frame.FrameNumber < frame.FrameNumber {
|
|
||||||
e.latestFrameReceived = frame.FrameNumber
|
|
||||||
e.lastFrameReceivedAt = time.Now().UTC()
|
|
||||||
}
|
|
||||||
e.frameSeenProverTrie.Add(address, frame.FrameNumber)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) publishProof(
|
func (e *CeremonyDataClockConsensusEngine) publishProof(
|
||||||
frame *protobufs.ClockFrame,
|
frame *protobufs.ClockFrame,
|
||||||
) error {
|
) error {
|
||||||
if e.state == consensus.EngineStatePublishing {
|
e.logger.Debug(
|
||||||
e.logger.Debug(
|
"publishing frame and aggregations",
|
||||||
"publishing frame and aggregations",
|
zap.Uint64("frame_number", frame.FrameNumber),
|
||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
)
|
||||||
|
if err := e.publishMessage(e.filter, frame); err != nil {
|
||||||
|
return errors.Wrap(
|
||||||
|
err,
|
||||||
|
"publish proof",
|
||||||
)
|
)
|
||||||
if err := e.publishMessage(e.filter, frame); err != nil {
|
|
||||||
return errors.Wrap(
|
|
||||||
err,
|
|
||||||
"publish proof",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
e.state = consensus.EngineStateCollecting
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package ceremony
|
package ceremony
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/big"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
|
qtime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
@ -53,7 +54,6 @@ type ChannelServer = protobufs.CeremonyService_GetPublicChannelServer
|
|||||||
|
|
||||||
type CeremonyDataClockConsensusEngine struct {
|
type CeremonyDataClockConsensusEngine struct {
|
||||||
protobufs.UnimplementedCeremonyServiceServer
|
protobufs.UnimplementedCeremonyServiceServer
|
||||||
frame *protobufs.ClockFrame
|
|
||||||
difficulty uint32
|
difficulty uint32
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
state consensus.EngineState
|
state consensus.EngineState
|
||||||
@ -61,6 +61,8 @@ type CeremonyDataClockConsensusEngine struct {
|
|||||||
keyStore store.KeyStore
|
keyStore store.KeyStore
|
||||||
pubSub p2p.PubSub
|
pubSub p2p.PubSub
|
||||||
keyManager keys.KeyManager
|
keyManager keys.KeyManager
|
||||||
|
masterTimeReel *qtime.MasterTimeReel
|
||||||
|
dataTimeReel *qtime.DataTimeReel
|
||||||
provingKey crypto.Signer
|
provingKey crypto.Signer
|
||||||
provingKeyBytes []byte
|
provingKeyBytes []byte
|
||||||
provingKeyType keys.KeyType
|
provingKeyType keys.KeyType
|
||||||
@ -68,13 +70,11 @@ type CeremonyDataClockConsensusEngine struct {
|
|||||||
lastFrameReceivedAt time.Time
|
lastFrameReceivedAt time.Time
|
||||||
latestFrameReceived uint64
|
latestFrameReceived uint64
|
||||||
frameProverTrie *tries.RollingFrecencyCritbitTrie
|
frameProverTrie *tries.RollingFrecencyCritbitTrie
|
||||||
frameSeenProverTrie *tries.RollingFrecencyCritbitTrie
|
|
||||||
dependencyMap map[string]*anypb.Any
|
dependencyMap map[string]*anypb.Any
|
||||||
pendingCommits chan *anypb.Any
|
pendingCommits chan *anypb.Any
|
||||||
pendingCommitWorkers int64
|
pendingCommitWorkers int64
|
||||||
prover *qcrypto.KZGProver
|
inclusionProver qcrypto.InclusionProver
|
||||||
stagedKeyCommits InclusionMap
|
frameProver qcrypto.FrameProver
|
||||||
stagedKeyPolynomials PolynomialMap
|
|
||||||
stagedLobbyStateTransitions *protobufs.CeremonyLobbyStateTransition
|
stagedLobbyStateTransitions *protobufs.CeremonyLobbyStateTransition
|
||||||
minimumPeersRequired int
|
minimumPeersRequired int
|
||||||
|
|
||||||
@ -86,10 +86,8 @@ type CeremonyDataClockConsensusEngine struct {
|
|||||||
syncingStatus SyncStatusType
|
syncingStatus SyncStatusType
|
||||||
syncingTarget []byte
|
syncingTarget []byte
|
||||||
previousHead *protobufs.ClockFrame
|
previousHead *protobufs.ClockFrame
|
||||||
currentDistance *big.Int
|
|
||||||
engineMx sync.Mutex
|
engineMx sync.Mutex
|
||||||
dependencyMapMx sync.Mutex
|
dependencyMapMx sync.Mutex
|
||||||
stagedKeyCommitsMx sync.Mutex
|
|
||||||
stagedLobbyStateTransitionsMx sync.Mutex
|
stagedLobbyStateTransitionsMx sync.Mutex
|
||||||
peerMapMx sync.Mutex
|
peerMapMx sync.Mutex
|
||||||
peerAnnounceMapMx sync.Mutex
|
peerAnnounceMapMx sync.Mutex
|
||||||
@ -112,6 +110,10 @@ func NewCeremonyDataClockConsensusEngine(
|
|||||||
clockStore store.ClockStore,
|
clockStore store.ClockStore,
|
||||||
keyStore store.KeyStore,
|
keyStore store.KeyStore,
|
||||||
pubSub p2p.PubSub,
|
pubSub p2p.PubSub,
|
||||||
|
frameProver qcrypto.FrameProver,
|
||||||
|
inclusionProver qcrypto.InclusionProver,
|
||||||
|
masterTimeReel *qtime.MasterTimeReel,
|
||||||
|
dataTimeReel *qtime.DataTimeReel,
|
||||||
filter []byte,
|
filter []byte,
|
||||||
seed []byte,
|
seed []byte,
|
||||||
) *CeremonyDataClockConsensusEngine {
|
) *CeremonyDataClockConsensusEngine {
|
||||||
@ -139,6 +141,22 @@ func NewCeremonyDataClockConsensusEngine(
|
|||||||
panic(errors.New("pubsub is nil"))
|
panic(errors.New("pubsub is nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if frameProver == nil {
|
||||||
|
panic(errors.New("frame prover is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if inclusionProver == nil {
|
||||||
|
panic(errors.New("inclusion prover is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if masterTimeReel == nil {
|
||||||
|
panic(errors.New("master time reel is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if dataTimeReel == nil {
|
||||||
|
panic(errors.New("data time reel is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
minimumPeersRequired := engineConfig.MinimumPeersRequired
|
minimumPeersRequired := engineConfig.MinimumPeersRequired
|
||||||
if minimumPeersRequired == 0 {
|
if minimumPeersRequired == 0 {
|
||||||
minimumPeersRequired = 3
|
minimumPeersRequired = 3
|
||||||
@ -150,7 +168,6 @@ func NewCeremonyDataClockConsensusEngine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
e := &CeremonyDataClockConsensusEngine{
|
e := &CeremonyDataClockConsensusEngine{
|
||||||
frame: nil,
|
|
||||||
difficulty: difficulty,
|
difficulty: difficulty,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
state: consensus.EngineStateStopped,
|
state: consensus.EngineStateStopped,
|
||||||
@ -169,17 +186,15 @@ func NewCeremonyDataClockConsensusEngine(
|
|||||||
},
|
},
|
||||||
lastFrameReceivedAt: time.Time{},
|
lastFrameReceivedAt: time.Time{},
|
||||||
frameProverTrie: &tries.RollingFrecencyCritbitTrie{},
|
frameProverTrie: &tries.RollingFrecencyCritbitTrie{},
|
||||||
frameSeenProverTrie: &tries.RollingFrecencyCritbitTrie{},
|
inclusionProver: inclusionProver,
|
||||||
pendingCommits: make(chan *anypb.Any),
|
|
||||||
pendingCommitWorkers: engineConfig.PendingCommitWorkers,
|
|
||||||
prover: qcrypto.DefaultKZGProver(),
|
|
||||||
stagedKeyCommits: make(InclusionMap),
|
|
||||||
stagedKeyPolynomials: make(PolynomialMap),
|
|
||||||
syncingStatus: SyncStatusNotSyncing,
|
syncingStatus: SyncStatusNotSyncing,
|
||||||
peerAnnounceMap: map[string]*protobufs.CeremonyPeerListAnnounce{},
|
peerAnnounceMap: map[string]*protobufs.CeremonyPeerListAnnounce{},
|
||||||
peerMap: map[string]*peerInfo{},
|
peerMap: map[string]*peerInfo{},
|
||||||
uncooperativePeersMap: map[string]*peerInfo{},
|
uncooperativePeersMap: map[string]*peerInfo{},
|
||||||
minimumPeersRequired: minimumPeersRequired,
|
minimumPeersRequired: minimumPeersRequired,
|
||||||
|
frameProver: frameProver,
|
||||||
|
masterTimeReel: masterTimeReel,
|
||||||
|
dataTimeReel: dataTimeReel,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("constructing consensus engine")
|
logger.Info("constructing consensus engine")
|
||||||
@ -205,30 +220,12 @@ func (e *CeremonyDataClockConsensusEngine) Start() <-chan error {
|
|||||||
e.state = consensus.EngineStateLoading
|
e.state = consensus.EngineStateLoading
|
||||||
|
|
||||||
e.logger.Info("loading last seen state")
|
e.logger.Info("loading last seen state")
|
||||||
latestFrame, err := e.clockStore.GetLatestDataClockFrame(
|
err := e.dataTimeReel.Start()
|
||||||
e.filter,
|
if err != nil {
|
||||||
e.frameProverTrie,
|
|
||||||
)
|
|
||||||
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
candidateLatestFrame, err := e.clockStore.GetLatestCandidateDataClockFrame(
|
e.frameProverTrie = e.dataTimeReel.GetFrameProverTrie()
|
||||||
e.filter,
|
|
||||||
)
|
|
||||||
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if candidateLatestFrame != nil {
|
|
||||||
latestFrame = candidateLatestFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
if latestFrame != nil {
|
|
||||||
e.setFrame(latestFrame)
|
|
||||||
} else {
|
|
||||||
latestFrame = e.CreateGenesisFrame(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = e.createCommunicationKeys()
|
err = e.createCommunicationKeys()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -255,10 +252,6 @@ func (e *CeremonyDataClockConsensusEngine) Start() <-chan error {
|
|||||||
|
|
||||||
e.state = consensus.EngineStateCollecting
|
e.state = consensus.EngineStateCollecting
|
||||||
|
|
||||||
for i := int64(0); i < e.pendingCommitWorkers; i++ {
|
|
||||||
go e.handlePendingCommits(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
thresholdBeforeConfirming := 4
|
thresholdBeforeConfirming := 4
|
||||||
|
|
||||||
@ -269,8 +262,13 @@ func (e *CeremonyDataClockConsensusEngine) Start() <-chan error {
|
|||||||
PeerList: []*protobufs.CeremonyPeer{},
|
PeerList: []*protobufs.CeremonyPeer{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame, err := e.dataTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
timestamp := time.Now().UnixMilli()
|
timestamp := time.Now().UnixMilli()
|
||||||
msg := binary.BigEndian.AppendUint64([]byte{}, e.frame.FrameNumber)
|
msg := binary.BigEndian.AppendUint64([]byte{}, frame.FrameNumber)
|
||||||
msg = append(msg, consensus.GetVersion()...)
|
msg = append(msg, consensus.GetVersion()...)
|
||||||
msg = binary.BigEndian.AppendUint64(msg, uint64(timestamp))
|
msg = binary.BigEndian.AppendUint64(msg, uint64(timestamp))
|
||||||
sig, err := e.pubSub.SignMessage(msg)
|
sig, err := e.pubSub.SignMessage(msg)
|
||||||
@ -282,7 +280,7 @@ func (e *CeremonyDataClockConsensusEngine) Start() <-chan error {
|
|||||||
e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{
|
e.peerMap[string(e.pubSub.GetPeerID())] = &peerInfo{
|
||||||
peerId: e.pubSub.GetPeerID(),
|
peerId: e.pubSub.GetPeerID(),
|
||||||
multiaddr: "",
|
multiaddr: "",
|
||||||
maxFrame: e.frame.FrameNumber,
|
maxFrame: frame.FrameNumber,
|
||||||
version: consensus.GetVersion(),
|
version: consensus.GetVersion(),
|
||||||
signature: sig,
|
signature: sig,
|
||||||
publicKey: e.pubSub.GetPublicKey(),
|
publicKey: e.pubSub.GetPublicKey(),
|
||||||
@ -325,42 +323,7 @@ func (e *CeremonyDataClockConsensusEngine) Start() <-chan error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
e.logger.Info("waiting for peer list mappings")
|
e.runLoop()
|
||||||
// We need to re-tune this so that libp2p's peerstore activation threshold
|
|
||||||
// considers DHT peers to be correct:
|
|
||||||
time.Sleep(30 * time.Second)
|
|
||||||
for e.state < consensus.EngineStateStopping {
|
|
||||||
peerCount := e.pubSub.GetNetworkPeersCount()
|
|
||||||
if peerCount < e.minimumPeersRequired {
|
|
||||||
e.logger.Info(
|
|
||||||
"waiting for minimum peers",
|
|
||||||
zap.Int("peer_count", peerCount),
|
|
||||||
)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
} else {
|
|
||||||
switch e.state {
|
|
||||||
case consensus.EngineStateCollecting:
|
|
||||||
currentFrame := latestFrame
|
|
||||||
if latestFrame, err = e.collect(latestFrame); err != nil {
|
|
||||||
e.logger.Error("could not collect", zap.Error(err))
|
|
||||||
e.state = consensus.EngineStateCollecting
|
|
||||||
latestFrame = currentFrame
|
|
||||||
}
|
|
||||||
case consensus.EngineStateProving:
|
|
||||||
currentFrame := latestFrame
|
|
||||||
if latestFrame, err = e.prove(latestFrame); err != nil {
|
|
||||||
e.logger.Error("could not prove", zap.Error(err))
|
|
||||||
e.state = consensus.EngineStateCollecting
|
|
||||||
latestFrame = currentFrame
|
|
||||||
}
|
|
||||||
case consensus.EngineStatePublishing:
|
|
||||||
if err = e.publishProof(latestFrame); err != nil {
|
|
||||||
e.logger.Error("could not publish", zap.Error(err))
|
|
||||||
e.state = consensus.EngineStateCollecting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -370,6 +333,86 @@ func (e *CeremonyDataClockConsensusEngine) Start() <-chan error {
|
|||||||
return errChan
|
return errChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *CeremonyDataClockConsensusEngine) runLoop() {
|
||||||
|
dataFrameCh := e.dataTimeReel.NewFrameCh()
|
||||||
|
|
||||||
|
e.logger.Info("waiting for peer list mappings")
|
||||||
|
// We need to re-tune this so that libp2p's peerstore activation threshold
|
||||||
|
// considers DHT peers to be correct:
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
|
||||||
|
for e.state < consensus.EngineStateStopping {
|
||||||
|
peerCount := e.pubSub.GetNetworkPeersCount()
|
||||||
|
if peerCount < e.minimumPeersRequired {
|
||||||
|
e.logger.Info(
|
||||||
|
"waiting for minimum peers",
|
||||||
|
zap.Int("peer_count", peerCount),
|
||||||
|
)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
} else {
|
||||||
|
latestFrame, err := e.dataTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case dataFrame := <-dataFrameCh:
|
||||||
|
if latestFrame, err = e.collect(dataFrame); err != nil {
|
||||||
|
e.logger.Error("could not collect", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
e.frameChan <- latestFrame
|
||||||
|
}()
|
||||||
|
|
||||||
|
var nextFrame *protobufs.ClockFrame
|
||||||
|
if nextFrame, err = e.prove(latestFrame); err != nil {
|
||||||
|
e.logger.Error("could not prove", zap.Error(err))
|
||||||
|
e.state = consensus.EngineStateCollecting
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(
|
||||||
|
e.frameProverTrie.FindNearest(e.provingKeyAddress).External.Key,
|
||||||
|
e.provingKeyAddress,
|
||||||
|
) {
|
||||||
|
if err = e.publishProof(nextFrame); err != nil {
|
||||||
|
e.logger.Error("could not publish", zap.Error(err))
|
||||||
|
e.state = consensus.EngineStateCollecting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-time.After(20 * time.Second):
|
||||||
|
e.logger.Info("no frames received, kicking off")
|
||||||
|
dataFrame, err := e.dataTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if latestFrame, err = e.collect(dataFrame); err != nil {
|
||||||
|
e.logger.Error("could not collect", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
e.frameChan <- latestFrame
|
||||||
|
}()
|
||||||
|
|
||||||
|
var nextFrame *protobufs.ClockFrame
|
||||||
|
if nextFrame, err = e.prove(latestFrame); err != nil {
|
||||||
|
e.logger.Error("could not prove", zap.Error(err))
|
||||||
|
e.state = consensus.EngineStateCollecting
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.frameProverTrie.Contains(e.provingKeyAddress) {
|
||||||
|
if err = e.publishProof(nextFrame); err != nil {
|
||||||
|
e.logger.Error("could not publish", zap.Error(err))
|
||||||
|
e.state = consensus.EngineStateCollecting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) Stop(force bool) <-chan error {
|
func (e *CeremonyDataClockConsensusEngine) Stop(force bool) <-chan error {
|
||||||
e.logger.Info("stopping ceremony consensus engine")
|
e.logger.Info("stopping ceremony consensus engine")
|
||||||
e.state = consensus.EngineStateStopping
|
e.state = consensus.EngineStateStopping
|
||||||
@ -380,7 +423,12 @@ func (e *CeremonyDataClockConsensusEngine) Stop(force bool) <-chan error {
|
|||||||
for name := range e.executionEngines {
|
for name := range e.executionEngines {
|
||||||
name := name
|
name := name
|
||||||
go func(name string) {
|
go func(name string) {
|
||||||
err := <-e.UnregisterExecutor(name, e.frame.FrameNumber, force)
|
frame, err := e.dataTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = <-e.UnregisterExecutor(name, frame.FrameNumber, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
@ -402,133 +450,17 @@ func (e *CeremonyDataClockConsensusEngine) Stop(force bool) <-chan error {
|
|||||||
return errChan
|
return errChan
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) performSanityCheck(
|
|
||||||
frame *protobufs.ClockFrame,
|
|
||||||
) *protobufs.ClockFrame {
|
|
||||||
e.logger.Info("performing sanity check")
|
|
||||||
start := uint64(0)
|
|
||||||
idx := start
|
|
||||||
end := frame.FrameNumber + 1
|
|
||||||
var prior *protobufs.ClockFrame
|
|
||||||
for start < end {
|
|
||||||
tail := end
|
|
||||||
if start+16 < tail {
|
|
||||||
tail = start + 16
|
|
||||||
}
|
|
||||||
iter, err := e.clockStore.RangeDataClockFrames(
|
|
||||||
e.filter,
|
|
||||||
start,
|
|
||||||
tail,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for iter.First(); iter.Valid(); iter.Next() {
|
|
||||||
v, err := iter.Value()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.FrameNumber != idx {
|
|
||||||
e.logger.Warn(
|
|
||||||
"discontinuity found, attempting to fix",
|
|
||||||
zap.Uint64("expected_frame_number", idx),
|
|
||||||
zap.Uint64("found_frame_number", v.FrameNumber),
|
|
||||||
)
|
|
||||||
|
|
||||||
disc := v
|
|
||||||
for disc.FrameNumber-idx > 0 {
|
|
||||||
frames, err := e.clockStore.GetCandidateDataClockFrames(
|
|
||||||
e.filter,
|
|
||||||
disc.FrameNumber-1,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, candidate := range frames {
|
|
||||||
selector, err := candidate.GetSelector()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentSelector, _, _, err := disc.GetParentSelectorAndDistance(nil)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if selector.Cmp(parentSelector) == 0 {
|
|
||||||
found = true
|
|
||||||
_, priorTrie, err := e.clockStore.GetDataClockFrame(
|
|
||||||
e.filter,
|
|
||||||
prior.FrameNumber,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
txn, err := e.clockStore.NewTransaction()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = e.clockStore.PutDataClockFrame(
|
|
||||||
candidate,
|
|
||||||
priorTrie,
|
|
||||||
txn,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = txn.Commit(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
disc = candidate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
e.logger.Error(
|
|
||||||
"could not resolve discontinuity, rewinding consensus head",
|
|
||||||
)
|
|
||||||
|
|
||||||
if err = iter.Close(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return prior
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = v.FrameNumber
|
|
||||||
} else {
|
|
||||||
prior = v
|
|
||||||
}
|
|
||||||
|
|
||||||
idx++
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = iter.Close(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
start += 16
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) GetDifficulty() uint32 {
|
func (e *CeremonyDataClockConsensusEngine) GetDifficulty() uint32 {
|
||||||
return e.difficulty
|
return e.difficulty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) GetFrame() *protobufs.ClockFrame {
|
func (e *CeremonyDataClockConsensusEngine) GetFrame() *protobufs.ClockFrame {
|
||||||
return e.frame
|
frame, err := e.dataTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) GetState() consensus.EngineState {
|
func (e *CeremonyDataClockConsensusEngine) GetState() consensus.EngineState {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,13 +15,18 @@ func (e *CeremonyDataClockConsensusEngine) RegisterExecutor(
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
masterFrame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"awaiting frame",
|
"awaiting frame",
|
||||||
zap.Uint64("current_frame", e.frame.FrameNumber),
|
zap.Uint64("current_frame", masterFrame.FrameNumber),
|
||||||
zap.Uint64("target_frame", frame),
|
zap.Uint64("target_frame", frame),
|
||||||
)
|
)
|
||||||
|
|
||||||
newFrame := e.frame.FrameNumber
|
newFrame := masterFrame.FrameNumber
|
||||||
if newFrame >= frame {
|
if newFrame >= frame {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"injecting execution engine at frame",
|
"injecting execution engine at frame",
|
||||||
@ -52,13 +57,18 @@ func (e *CeremonyDataClockConsensusEngine) UnregisterExecutor(
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
masterFrame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"awaiting frame",
|
"awaiting frame",
|
||||||
zap.Uint64("current_frame", e.frame.FrameNumber),
|
zap.Uint64("current_frame", masterFrame.FrameNumber),
|
||||||
zap.Uint64("target_frame", frame),
|
zap.Uint64("target_frame", frame),
|
||||||
)
|
)
|
||||||
|
|
||||||
newFrame := e.frame.FrameNumber
|
newFrame := masterFrame.FrameNumber
|
||||||
if newFrame >= frame {
|
if newFrame >= frame {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"removing execution engine at frame",
|
"removing execution engine at frame",
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
package ceremony
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) handlePendingCommits(
|
|
||||||
workerId int64,
|
|
||||||
) {
|
|
||||||
for {
|
|
||||||
msg := <-e.pendingCommits
|
|
||||||
switch msg.TypeUrl {
|
|
||||||
case protobufs.KeyBundleAnnouncementType:
|
|
||||||
if err := e.includeKeyBundle(msg); err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"failed to include key bundle",
|
|
||||||
zap.Error(errors.Wrap(err, "handle pending commits")),
|
|
||||||
zap.Int64("worker_id", workerId),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *CeremonyDataClockConsensusEngine) includeKeyBundle(
|
|
||||||
any *anypb.Any,
|
|
||||||
) error {
|
|
||||||
poly, err := e.prover.BytesToPolynomial(any.Value)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error converting key bundle to polynomial",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "include key bundle")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 128-len(poly); i++ {
|
|
||||||
poly = append(
|
|
||||||
poly,
|
|
||||||
curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
evalPoly, err := crypto.FFT(
|
|
||||||
poly,
|
|
||||||
*curves.BLS48581(
|
|
||||||
curves.BLS48581G1().NewGeneratorPoint(),
|
|
||||||
),
|
|
||||||
128,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error performing fast fourier transform on key bundle",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "include key bundle")
|
|
||||||
}
|
|
||||||
|
|
||||||
commitment, err := e.prover.Commit(evalPoly)
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"error creating kzg commitment",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return errors.Wrap(err, "include key bundle")
|
|
||||||
}
|
|
||||||
|
|
||||||
e.stagedKeyCommitsMx.Lock()
|
|
||||||
e.stagedKeyCommits[commitment] = &protobufs.InclusionCommitment{
|
|
||||||
Filter: e.filter,
|
|
||||||
TypeUrl: any.TypeUrl,
|
|
||||||
Data: any.Value,
|
|
||||||
Commitment: commitment.ToAffineCompressed(),
|
|
||||||
}
|
|
||||||
e.stagedKeyPolynomials[commitment] = evalPoly
|
|
||||||
e.stagedKeyCommitsMx.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony/application"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
@ -106,7 +106,12 @@ func (e *CeremonyDataClockConsensusEngine) GetCompressedSyncFrames(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
max := e.frame.FrameNumber
|
head, err := e.dataTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
max := head.FrameNumber
|
||||||
to := request.ToFrameNumber
|
to := request.ToFrameNumber
|
||||||
|
|
||||||
// We need to slightly rewind, to compensate for unconfirmed frame heads on a
|
// We need to slightly rewind, to compensate for unconfirmed frame heads on a
|
||||||
|
@ -51,13 +51,13 @@ type DataConsensusEngine interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetMinimumVersionCutoff() time.Time {
|
func GetMinimumVersionCutoff() time.Time {
|
||||||
return time.Date(2024, time.January, 14, 7, 0, 0, 0, time.UTC)
|
return time.Date(2024, time.February, 13, 7, 0, 0, 0, time.UTC)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMinimumVersion() []byte {
|
func GetMinimumVersion() []byte {
|
||||||
return []byte{0x01, 0x02, 0x03}
|
return []byte{0x01, 0x02, 0x04}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetVersion() []byte {
|
func GetVersion() []byte {
|
||||||
return []byte{0x01, 0x02, 0x03}
|
return []byte{0x01, 0x02, 0x04}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package master
|
package master
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -92,17 +90,6 @@ func (e *MasterClockConsensusEngine) handleClockFrameData(
|
|||||||
return errors.Wrap(err, "handle clock frame data")
|
return errors.Wrap(err, "handle clock frame data")
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.frame.FrameNumber > frame.FrameNumber {
|
|
||||||
e.logger.Debug(
|
|
||||||
"received anachronistic frame",
|
|
||||||
zap.Binary("sender", peerID),
|
|
||||||
zap.Binary("filter", frame.Filter),
|
|
||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
|
||||||
zap.Int("proof_count", len(frame.AggregateProofs)),
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.difficulty != frame.Difficulty {
|
if e.difficulty != frame.Difficulty {
|
||||||
e.logger.Debug(
|
e.logger.Debug(
|
||||||
"frame difficulty mismatched",
|
"frame difficulty mismatched",
|
||||||
@ -122,65 +109,35 @@ func (e *MasterClockConsensusEngine) handleClockFrameData(
|
|||||||
zap.Int("proof_count", len(frame.AggregateProofs)),
|
zap.Int("proof_count", len(frame.AggregateProofs)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := frame.VerifyMasterClockFrame(); err != nil {
|
if err := e.frameProver.VerifyMasterClockFrame(frame); err != nil {
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
e.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
return errors.Wrap(err, "handle clock frame data")
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.frame.FrameNumber < frame.FrameNumber {
|
e.masterTimeReel.Insert(frame)
|
||||||
if err := e.enqueueSeenFrame(frame); err != nil {
|
|
||||||
e.logger.Error("could not enqueue seen clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame data")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MasterClockConsensusEngine) enqueueSeenFrame(
|
|
||||||
frame *protobufs.ClockFrame,
|
|
||||||
) error {
|
|
||||||
e.seenFramesMx.Lock()
|
|
||||||
found := false
|
|
||||||
for _, f := range e.seenFrames {
|
|
||||||
if f.FrameNumber == frame.FrameNumber &&
|
|
||||||
bytes.Equal(f.Input, frame.Input) &&
|
|
||||||
f.Difficulty == frame.Difficulty &&
|
|
||||||
bytes.Equal(f.Output, frame.Output) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
e.logger.Debug(
|
|
||||||
"enqueuing frame for consensus",
|
|
||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
|
||||||
)
|
|
||||||
e.seenFrames = append(e.seenFrames, frame)
|
|
||||||
e.lastFrameReceivedAt = time.Now().UTC()
|
|
||||||
}
|
|
||||||
e.seenFramesMx.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *MasterClockConsensusEngine) publishProof(
|
func (e *MasterClockConsensusEngine) publishProof(
|
||||||
frame *protobufs.ClockFrame,
|
frame *protobufs.ClockFrame,
|
||||||
) error {
|
) error {
|
||||||
if e.state == consensus.EngineStatePublishing {
|
e.logger.Debug(
|
||||||
e.logger.Debug(
|
"publishing frame",
|
||||||
"publishing frame",
|
zap.Uint64("frame_number", frame.FrameNumber),
|
||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
)
|
||||||
)
|
|
||||||
e.enqueueSeenFrame(frame)
|
|
||||||
if err := e.publishMessage(e.filter, frame); err != nil {
|
|
||||||
return errors.Wrap(
|
|
||||||
err,
|
|
||||||
"publish proof",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
e.state = consensus.EngineStateCollecting
|
e.masterTimeReel.Insert(frame)
|
||||||
|
|
||||||
|
if err := e.publishMessage(e.filter, frame); err != nil {
|
||||||
|
return errors.Wrap(
|
||||||
|
err,
|
||||||
|
"publish proof",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.state = consensus.EngineStateCollecting
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
package master
|
package master
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"sort"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
@ -19,250 +14,92 @@ import (
|
|||||||
func (e *MasterClockConsensusEngine) prove(
|
func (e *MasterClockConsensusEngine) prove(
|
||||||
previousFrame *protobufs.ClockFrame,
|
previousFrame *protobufs.ClockFrame,
|
||||||
) (*protobufs.ClockFrame, error) {
|
) (*protobufs.ClockFrame, error) {
|
||||||
if e.state == consensus.EngineStateProving {
|
e.logger.Debug("proving new frame")
|
||||||
e.logger.Debug("proving new frame")
|
|
||||||
|
|
||||||
frame, err := protobufs.ProveMasterClockFrame(
|
frame, err := e.frameProver.ProveMasterClockFrame(
|
||||||
previousFrame,
|
previousFrame,
|
||||||
e.difficulty,
|
time.Now().UnixMilli(),
|
||||||
)
|
e.difficulty,
|
||||||
if err != nil {
|
)
|
||||||
return nil, errors.Wrap(err, "prove")
|
if err != nil {
|
||||||
}
|
return nil, errors.Wrap(err, "prove")
|
||||||
|
|
||||||
e.state = consensus.EngineStatePublishing
|
|
||||||
e.logger.Debug("returning new proven frame")
|
|
||||||
return frame, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
e.state = consensus.EngineStatePublishing
|
||||||
}
|
e.logger.Debug("returning new proven frame")
|
||||||
|
return frame, nil
|
||||||
func (e *MasterClockConsensusEngine) setFrame(frame *protobufs.ClockFrame) {
|
|
||||||
previousSelectorBytes := [516]byte{}
|
|
||||||
copy(previousSelectorBytes[:], frame.Output[:516])
|
|
||||||
|
|
||||||
e.logger.Debug("set frame", zap.Uint64("frame_number", frame.FrameNumber))
|
|
||||||
e.frame = frame
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
e.frameChan <- e.frame
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (
|
|
||||||
e *MasterClockConsensusEngine,
|
|
||||||
) CreateGenesisFrame() *protobufs.ClockFrame {
|
|
||||||
e.logger.Debug("creating genesis frame")
|
|
||||||
b := sha3.Sum256(e.input)
|
|
||||||
v := vdf.New(e.difficulty, b)
|
|
||||||
|
|
||||||
v.Execute()
|
|
||||||
o := v.GetOutput()
|
|
||||||
inputMessage := o[:]
|
|
||||||
|
|
||||||
e.logger.Debug("proving genesis frame")
|
|
||||||
input := []byte{}
|
|
||||||
input = append(input, e.filter...)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, 0)
|
|
||||||
input = binary.BigEndian.AppendUint32(input, e.difficulty)
|
|
||||||
if bytes.Equal(e.input, []byte{0x00}) {
|
|
||||||
value := [516]byte{}
|
|
||||||
input = append(input, value[:]...)
|
|
||||||
} else {
|
|
||||||
input = append(input, e.input...)
|
|
||||||
}
|
|
||||||
|
|
||||||
b = sha3.Sum256(input)
|
|
||||||
v = vdf.New(e.difficulty, b)
|
|
||||||
|
|
||||||
v.Execute()
|
|
||||||
o = v.GetOutput()
|
|
||||||
|
|
||||||
frame := &protobufs.ClockFrame{
|
|
||||||
Filter: e.filter,
|
|
||||||
FrameNumber: 0,
|
|
||||||
Timestamp: 0,
|
|
||||||
Difficulty: e.difficulty,
|
|
||||||
Input: inputMessage,
|
|
||||||
Output: o[:],
|
|
||||||
ParentSelector: []byte{
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
},
|
|
||||||
AggregateProofs: []*protobufs.InclusionAggregateProof{},
|
|
||||||
PublicKeySignature: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
e.setFrame(frame)
|
|
||||||
return frame
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MasterClockConsensusEngine) collect(
|
func (e *MasterClockConsensusEngine) collect(
|
||||||
currentFramePublished *protobufs.ClockFrame,
|
currentFramePublished *protobufs.ClockFrame,
|
||||||
) (*protobufs.ClockFrame, error) {
|
) (*protobufs.ClockFrame, error) {
|
||||||
if e.state == consensus.EngineStateCollecting {
|
e.logger.Debug("collecting vdf proofs")
|
||||||
e.logger.Debug("collecting vdf proofs")
|
|
||||||
|
|
||||||
latest := e.frame
|
latest, err := e.masterTimeReel.Head()
|
||||||
|
|
||||||
if e.syncingStatus == SyncStatusNotSyncing {
|
|
||||||
peer, err := e.pubSub.GetRandomPeer(e.filter)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, p2p.ErrNoPeersAvailable) {
|
|
||||||
e.logger.Debug("no peers available, skipping sync")
|
|
||||||
} else {
|
|
||||||
e.logger.Error("error while fetching random peer", zap.Error(err))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
e.syncingStatus = SyncStatusAwaitingResponse
|
|
||||||
e.logger.Debug("setting syncing target", zap.Binary("peer_id", peer))
|
|
||||||
e.syncingTarget = peer
|
|
||||||
|
|
||||||
channel := e.createPeerReceiveChannel(peer)
|
|
||||||
e.logger.Debug(
|
|
||||||
"listening on peer receive channel",
|
|
||||||
zap.Binary("channel", channel),
|
|
||||||
)
|
|
||||||
e.pubSub.Subscribe(channel, e.handleSync, true)
|
|
||||||
e.pubSub.Subscribe(
|
|
||||||
peer,
|
|
||||||
func(message *pb.Message) error { return nil },
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
if err := e.publishMessage(peer, &protobufs.ClockFramesRequest{
|
|
||||||
Filter: e.filter,
|
|
||||||
FromFrameNumber: latest.FrameNumber + 1,
|
|
||||||
}); err != nil {
|
|
||||||
e.logger.Error(
|
|
||||||
"could not publish clock frame request",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
waitDecay := time.Duration(2000)
|
|
||||||
for e.syncingStatus != SyncStatusNotSyncing {
|
|
||||||
e.logger.Debug(
|
|
||||||
"waiting for sync to complete...",
|
|
||||||
zap.Duration("wait_decay", waitDecay),
|
|
||||||
)
|
|
||||||
|
|
||||||
time.Sleep(waitDecay * time.Millisecond)
|
|
||||||
|
|
||||||
waitDecay = waitDecay * 2
|
|
||||||
if waitDecay >= (100 * (2 << 6)) {
|
|
||||||
if e.syncingStatus == SyncStatusAwaitingResponse {
|
|
||||||
e.logger.Debug("maximum wait for sync response, skipping sync")
|
|
||||||
e.syncingStatus = SyncStatusNotSyncing
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
waitDecay = 100 * (2 << 6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.logger.Debug("selecting leader")
|
|
||||||
latestFrame, err := e.confirmLatestFrame()
|
|
||||||
if err != nil {
|
|
||||||
e.logger.Error("could not confirm latest frame", zap.Error(err))
|
|
||||||
return nil, errors.Wrap(err, "collect")
|
|
||||||
}
|
|
||||||
|
|
||||||
e.logger.Debug(
|
|
||||||
"returning leader frame",
|
|
||||||
zap.Uint64("frame_number", latestFrame.FrameNumber),
|
|
||||||
)
|
|
||||||
|
|
||||||
e.state = consensus.EngineStateProving
|
|
||||||
return latestFrame, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (
|
|
||||||
e *MasterClockConsensusEngine,
|
|
||||||
) confirmLatestFrame() (*protobufs.ClockFrame, error) {
|
|
||||||
e.seenFramesMx.Lock()
|
|
||||||
defer e.seenFramesMx.Unlock()
|
|
||||||
|
|
||||||
sort.Slice(e.seenFrames, func(i, j int) bool {
|
|
||||||
return e.seenFrames[i].FrameNumber < e.seenFrames[j].FrameNumber
|
|
||||||
})
|
|
||||||
|
|
||||||
if len(e.seenFrames) == 0 {
|
|
||||||
return e.frame, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
prev := e.frame
|
|
||||||
committedSet := []*protobufs.ClockFrame{}
|
|
||||||
|
|
||||||
for len(e.seenFrames) > 0 {
|
|
||||||
curr := e.seenFrames[0]
|
|
||||||
e.seenFrames = e.seenFrames[1:]
|
|
||||||
|
|
||||||
e.logger.Debug(
|
|
||||||
"checking continuity for frame",
|
|
||||||
zap.Uint64("frame_number", curr.FrameNumber),
|
|
||||||
)
|
|
||||||
|
|
||||||
if prev.FrameNumber+1 < curr.FrameNumber ||
|
|
||||||
prev.FrameNumber > curr.FrameNumber {
|
|
||||||
e.logger.Debug(
|
|
||||||
"continuity break found",
|
|
||||||
zap.Uint64("prev_frame_number", prev.FrameNumber),
|
|
||||||
zap.Uint64("curr_frame_number", curr.FrameNumber),
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes.Equal(prev.Output, curr.Input[:516]) {
|
|
||||||
prev = curr
|
|
||||||
committedSet = append(committedSet, prev)
|
|
||||||
} else {
|
|
||||||
e.logger.Debug("frame mismatch on input/output")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
txn, err := e.clockStore.NewTransaction()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.logger.Error("error while creating transaction", zap.Error(err))
|
panic(err)
|
||||||
return nil, errors.Wrap(err, "confirm latest frame")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, frame := range committedSet {
|
if e.syncingStatus == SyncStatusNotSyncing {
|
||||||
frame := frame
|
peer, err := e.pubSub.GetRandomPeer(e.filter)
|
||||||
if err = e.clockStore.PutMasterClockFrame(frame, txn); err != nil {
|
if err != nil {
|
||||||
e.logger.Error("error while committing frame", zap.Error(err))
|
if errors.Is(err, p2p.ErrNoPeersAvailable) {
|
||||||
return nil, errors.Wrap(err, "confirm latest frame")
|
e.logger.Debug("no peers available, skipping sync")
|
||||||
|
} else {
|
||||||
|
e.logger.Error("error while fetching random peer", zap.Error(err))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e.syncingStatus = SyncStatusAwaitingResponse
|
||||||
|
e.logger.Debug("setting syncing target", zap.Binary("peer_id", peer))
|
||||||
|
e.syncingTarget = peer
|
||||||
|
|
||||||
|
channel := e.createPeerReceiveChannel(peer)
|
||||||
|
e.logger.Debug(
|
||||||
|
"listening on peer receive channel",
|
||||||
|
zap.Binary("channel", channel),
|
||||||
|
)
|
||||||
|
e.pubSub.Subscribe(channel, e.handleSync, true)
|
||||||
|
e.pubSub.Subscribe(
|
||||||
|
peer,
|
||||||
|
func(message *pb.Message) error { return nil },
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
if err := e.publishMessage(peer, &protobufs.ClockFramesRequest{
|
||||||
|
Filter: e.filter,
|
||||||
|
FromFrameNumber: latest.FrameNumber + 1,
|
||||||
|
}); err != nil {
|
||||||
|
e.logger.Error(
|
||||||
|
"could not publish clock frame request",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = txn.Commit(); err != nil {
|
waitDecay := time.Duration(2000)
|
||||||
e.logger.Error("error while committing transaction", zap.Error(err))
|
for e.syncingStatus != SyncStatusNotSyncing {
|
||||||
return nil, errors.Wrap(err, "confirm latest frame")
|
e.logger.Debug(
|
||||||
|
"waiting for sync to complete...",
|
||||||
|
zap.Duration("wait_decay", waitDecay),
|
||||||
|
)
|
||||||
|
|
||||||
|
time.Sleep(waitDecay * time.Millisecond)
|
||||||
|
|
||||||
|
waitDecay = waitDecay * 2
|
||||||
|
if waitDecay >= (100 * (2 << 6)) {
|
||||||
|
if e.syncingStatus == SyncStatusAwaitingResponse {
|
||||||
|
e.logger.Debug("maximum wait for sync response, skipping sync")
|
||||||
|
e.syncingStatus = SyncStatusNotSyncing
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
waitDecay = 100 * (2 << 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.logger.Debug("stored frames", zap.Int("frame_count", len(committedSet)))
|
return latest, nil
|
||||||
|
|
||||||
e.historicFramesMx.Lock()
|
|
||||||
|
|
||||||
e.historicFrames = append(e.historicFrames, committedSet...)
|
|
||||||
if len(e.historicFrames) > 256 {
|
|
||||||
e.historicFrames = e.historicFrames[len(e.historicFrames)-256:]
|
|
||||||
}
|
|
||||||
|
|
||||||
e.historicFramesMx.Unlock()
|
|
||||||
|
|
||||||
e.setFrame(prev)
|
|
||||||
|
|
||||||
return prev, nil
|
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,16 @@ func (e *MasterClockConsensusEngine) RegisterExecutor(
|
|||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
masterFrame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"starting execution engine at frame",
|
"starting execution engine at frame",
|
||||||
zap.Uint64("current_frame", e.frame.FrameNumber),
|
zap.Uint64("current_frame", masterFrame.FrameNumber),
|
||||||
)
|
)
|
||||||
err := <-exec.Start()
|
err = <-exec.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("could not start execution engine", zap.Error(err))
|
logger.Error("could not start execution engine", zap.Error(err))
|
||||||
errChan <- err
|
errChan <- err
|
||||||
@ -27,13 +32,18 @@ func (e *MasterClockConsensusEngine) RegisterExecutor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
masterFrame, err = e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"awaiting frame",
|
"awaiting frame",
|
||||||
zap.Uint64("current_frame", e.frame.FrameNumber),
|
zap.Uint64("current_frame", masterFrame.FrameNumber),
|
||||||
zap.Uint64("target_frame", frame),
|
zap.Uint64("target_frame", frame),
|
||||||
)
|
)
|
||||||
|
|
||||||
newFrame := e.frame.FrameNumber
|
newFrame := masterFrame.FrameNumber
|
||||||
if newFrame >= frame {
|
if newFrame >= frame {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"injecting execution engine at frame",
|
"injecting execution engine at frame",
|
||||||
@ -74,13 +84,18 @@ func (e *MasterClockConsensusEngine) UnregisterExecutor(
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
masterFrame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"awaiting frame",
|
"awaiting frame",
|
||||||
zap.Uint64("current_frame", e.frame.FrameNumber),
|
zap.Uint64("current_frame", masterFrame.FrameNumber),
|
||||||
zap.Uint64("target_frame", frame),
|
zap.Uint64("target_frame", frame),
|
||||||
)
|
)
|
||||||
|
|
||||||
newFrame := e.frame.FrameNumber
|
newFrame := masterFrame.FrameNumber
|
||||||
if newFrame >= frame {
|
if newFrame >= frame {
|
||||||
logger.Info(
|
logger.Info(
|
||||||
"removing execution engine at frame",
|
"removing execution engine at frame",
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus"
|
||||||
|
qtime "source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
@ -25,12 +27,12 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MasterClockConsensusEngine struct {
|
type MasterClockConsensusEngine struct {
|
||||||
frame *protobufs.ClockFrame
|
|
||||||
difficulty uint32
|
difficulty uint32
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
state consensus.EngineState
|
state consensus.EngineState
|
||||||
pubSub p2p.PubSub
|
pubSub p2p.PubSub
|
||||||
keyManager keys.KeyManager
|
keyManager keys.KeyManager
|
||||||
|
frameProver crypto.FrameProver
|
||||||
lastFrameReceivedAt time.Time
|
lastFrameReceivedAt time.Time
|
||||||
|
|
||||||
frameChan chan *protobufs.ClockFrame
|
frameChan chan *protobufs.ClockFrame
|
||||||
@ -45,6 +47,7 @@ type MasterClockConsensusEngine struct {
|
|||||||
seenFrames []*protobufs.ClockFrame
|
seenFrames []*protobufs.ClockFrame
|
||||||
historicFrames []*protobufs.ClockFrame
|
historicFrames []*protobufs.ClockFrame
|
||||||
clockStore store.ClockStore
|
clockStore store.ClockStore
|
||||||
|
masterTimeReel *qtime.MasterTimeReel
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ consensus.ConsensusEngine = (*MasterClockConsensusEngine)(nil)
|
var _ consensus.ConsensusEngine = (*MasterClockConsensusEngine)(nil)
|
||||||
@ -55,6 +58,8 @@ func NewMasterClockConsensusEngine(
|
|||||||
clockStore store.ClockStore,
|
clockStore store.ClockStore,
|
||||||
keyManager keys.KeyManager,
|
keyManager keys.KeyManager,
|
||||||
pubSub p2p.PubSub,
|
pubSub p2p.PubSub,
|
||||||
|
frameProver crypto.FrameProver,
|
||||||
|
masterTimeReel *qtime.MasterTimeReel,
|
||||||
) *MasterClockConsensusEngine {
|
) *MasterClockConsensusEngine {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
panic(errors.New("logger is nil"))
|
panic(errors.New("logger is nil"))
|
||||||
@ -72,13 +77,20 @@ func NewMasterClockConsensusEngine(
|
|||||||
panic(errors.New("pubsub is nil"))
|
panic(errors.New("pubsub is nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if frameProver == nil {
|
||||||
|
panic(errors.New("frame prover is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if masterTimeReel == nil {
|
||||||
|
panic(errors.New("master time reel is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
seed, err := hex.DecodeString(engineConfig.GenesisSeed)
|
seed, err := hex.DecodeString(engineConfig.GenesisSeed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(errors.New("genesis seed is nil"))
|
panic(errors.New("genesis seed is nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
e := &MasterClockConsensusEngine{
|
e := &MasterClockConsensusEngine{
|
||||||
frame: nil,
|
|
||||||
difficulty: 10000,
|
difficulty: 10000,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
state: consensus.EngineStateStopped,
|
state: consensus.EngineStateStopped,
|
||||||
@ -90,15 +102,8 @@ func NewMasterClockConsensusEngine(
|
|||||||
lastFrameReceivedAt: time.Time{},
|
lastFrameReceivedAt: time.Time{},
|
||||||
syncingStatus: SyncStatusNotSyncing,
|
syncingStatus: SyncStatusNotSyncing,
|
||||||
clockStore: clockStore,
|
clockStore: clockStore,
|
||||||
}
|
frameProver: frameProver,
|
||||||
|
masterTimeReel: masterTimeReel,
|
||||||
latestFrame, err := e.clockStore.GetLatestMasterClockFrame(e.filter)
|
|
||||||
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if latestFrame != nil {
|
|
||||||
e.frame = latestFrame
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.filter, err = hex.DecodeString(engineConfig.Filter); err != nil {
|
if e.filter, err = hex.DecodeString(engineConfig.Filter); err != nil {
|
||||||
@ -118,28 +123,17 @@ func (e *MasterClockConsensusEngine) Start() <-chan error {
|
|||||||
e.state = consensus.EngineStateLoading
|
e.state = consensus.EngineStateLoading
|
||||||
e.logger.Info("syncing last seen state")
|
e.logger.Info("syncing last seen state")
|
||||||
|
|
||||||
latestFrame, err := e.clockStore.GetLatestMasterClockFrame(e.filter)
|
err := e.masterTimeReel.Start()
|
||||||
if err != nil && errors.Is(err, store.ErrNotFound) {
|
if err != nil {
|
||||||
latestFrame = e.CreateGenesisFrame()
|
|
||||||
txn, err := e.clockStore.NewTransaction()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = e.clockStore.PutMasterClockFrame(latestFrame, txn); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = txn.Commit(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
} else {
|
|
||||||
e.setFrame(latestFrame)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.buildHistoricFrameCache(latestFrame)
|
frame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.buildHistoricFrameCache(frame)
|
||||||
|
|
||||||
e.logger.Info("subscribing to pubsub messages")
|
e.logger.Info("subscribing to pubsub messages")
|
||||||
e.pubSub.Subscribe(e.filter, e.handleMessage, true)
|
e.pubSub.Subscribe(e.filter, e.handleMessage, true)
|
||||||
@ -159,25 +153,39 @@ func (e *MasterClockConsensusEngine) Start() <-chan error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
newFrameCh := e.masterTimeReel.NewFrameCh()
|
||||||
|
|
||||||
for e.state < consensus.EngineStateStopping {
|
for e.state < consensus.EngineStateStopping {
|
||||||
var err error
|
var err error
|
||||||
switch e.state {
|
select {
|
||||||
case consensus.EngineStateCollecting:
|
case frame := <-newFrameCh:
|
||||||
currentFrame := latestFrame
|
currentFrame := frame
|
||||||
if latestFrame, err = e.collect(latestFrame); err != nil {
|
latestFrame := frame
|
||||||
|
if latestFrame, err = e.collect(currentFrame); err != nil {
|
||||||
e.logger.Error("could not collect", zap.Error(err))
|
e.logger.Error("could not collect", zap.Error(err))
|
||||||
latestFrame = currentFrame
|
latestFrame = currentFrame
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
case consensus.EngineStateProving:
|
|
||||||
currentFrame := latestFrame
|
|
||||||
if latestFrame, err = e.prove(latestFrame); err != nil {
|
if latestFrame, err = e.prove(latestFrame); err != nil {
|
||||||
e.logger.Error("could not prove", zap.Error(err))
|
e.logger.Error("could not prove", zap.Error(err))
|
||||||
latestFrame = currentFrame
|
latestFrame = currentFrame
|
||||||
}
|
}
|
||||||
case consensus.EngineStatePublishing:
|
|
||||||
if err = e.publishProof(latestFrame); err != nil {
|
if err = e.publishProof(latestFrame); err != nil {
|
||||||
e.logger.Error("could not publish", zap.Error(err))
|
e.logger.Error("could not publish", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
case <-time.After(20 * time.Second):
|
||||||
|
frame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame, err = e.prove(frame); err != nil {
|
||||||
|
e.logger.Error("could not prove", zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = e.publishProof(frame); err != nil {
|
||||||
|
e.logger.Error("could not publish", zap.Error(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -199,7 +207,13 @@ func (e *MasterClockConsensusEngine) Stop(force bool) <-chan error {
|
|||||||
for name := range e.executionEngines {
|
for name := range e.executionEngines {
|
||||||
name := name
|
name := name
|
||||||
go func(name string) {
|
go func(name string) {
|
||||||
err := <-e.UnregisterExecutor(name, e.frame.FrameNumber, force)
|
frame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = <-e.UnregisterExecutor(name, frame.FrameNumber, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
@ -210,6 +224,7 @@ func (e *MasterClockConsensusEngine) Stop(force bool) <-chan error {
|
|||||||
e.logger.Info("waiting for execution engines to stop")
|
e.logger.Info("waiting for execution engines to stop")
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
e.logger.Info("execution engines stopped")
|
e.logger.Info("execution engines stopped")
|
||||||
|
e.masterTimeReel.Stop()
|
||||||
|
|
||||||
e.state = consensus.EngineStateStopped
|
e.state = consensus.EngineStateStopped
|
||||||
go func() {
|
go func() {
|
||||||
@ -223,7 +238,12 @@ func (e *MasterClockConsensusEngine) GetDifficulty() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *MasterClockConsensusEngine) GetFrame() *protobufs.ClockFrame {
|
func (e *MasterClockConsensusEngine) GetFrame() *protobufs.ClockFrame {
|
||||||
return e.frame
|
frame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MasterClockConsensusEngine) GetState() consensus.EngineState {
|
func (e *MasterClockConsensusEngine) GetState() consensus.EngineState {
|
||||||
|
@ -96,7 +96,7 @@ func (e *MasterClockConsensusEngine) handleClockFramesResponse(
|
|||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
zap.Uint64("frame_number", frame.FrameNumber),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := frame.VerifyMasterClockFrame(); err != nil {
|
if err := e.frameProver.VerifyMasterClockFrame(frame); err != nil {
|
||||||
e.logger.Error("could not verify clock frame", zap.Error(err))
|
e.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
return errors.Wrap(err, "handle clock frame response")
|
return errors.Wrap(err, "handle clock frame response")
|
||||||
}
|
}
|
||||||
@ -108,12 +108,7 @@ func (e *MasterClockConsensusEngine) handleClockFramesResponse(
|
|||||||
zap.Uint64("frame_number", frame.FrameNumber),
|
zap.Uint64("frame_number", frame.FrameNumber),
|
||||||
)
|
)
|
||||||
|
|
||||||
if e.frame.FrameNumber < frame.FrameNumber {
|
e.masterTimeReel.Insert(frame)
|
||||||
if err := e.enqueueSeenFrame(frame); err != nil {
|
|
||||||
e.logger.Error("could not enqueue seen clock frame", zap.Error(err))
|
|
||||||
return errors.Wrap(err, "handle clock frame response")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -145,7 +140,12 @@ func (e *MasterClockConsensusEngine) handleClockFramesRequest(
|
|||||||
|
|
||||||
from := request.FromFrameNumber
|
from := request.FromFrameNumber
|
||||||
|
|
||||||
if e.frame.FrameNumber < from || len(e.historicFrames) == 0 {
|
masterFrame, err := e.masterTimeReel.Head()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if masterFrame.FrameNumber < from || len(e.historicFrames) == 0 {
|
||||||
e.logger.Debug(
|
e.logger.Debug(
|
||||||
"peer asked for undiscovered frame",
|
"peer asked for undiscovered frame",
|
||||||
zap.Binary("peer_id", peerID),
|
zap.Binary("peer_id", peerID),
|
||||||
@ -169,8 +169,8 @@ func (e *MasterClockConsensusEngine) handleClockFramesRequest(
|
|||||||
to = request.FromFrameNumber + 127
|
to = request.FromFrameNumber + 127
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(to) > int(e.frame.FrameNumber) {
|
if int(to) > int(masterFrame.FrameNumber) {
|
||||||
to = e.frame.FrameNumber
|
to = masterFrame.FrameNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
e.logger.Debug(
|
e.logger.Debug(
|
||||||
|
607
node/consensus/time/data_time_reel.go
Normal file
607
node/consensus/time/data_time_reel.go
Normal file
@ -0,0 +1,607 @@
|
|||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
||||||
|
)
|
||||||
|
|
||||||
|
var allBitmaskFilter = []byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
}
|
||||||
|
|
||||||
|
var unknownDistance = new(big.Int).SetBytes([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
})
|
||||||
|
|
||||||
|
type pendingFrame struct {
|
||||||
|
parentSelector *big.Int
|
||||||
|
distance *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataTimeReel struct {
|
||||||
|
rwMutex sync.RWMutex
|
||||||
|
|
||||||
|
filter []byte
|
||||||
|
engineConfig *config.EngineConfig
|
||||||
|
logger *zap.Logger
|
||||||
|
clockStore store.ClockStore
|
||||||
|
frameProver crypto.FrameProver
|
||||||
|
parentTimeReel TimeReel
|
||||||
|
|
||||||
|
origin []byte
|
||||||
|
initialInclusionProof *crypto.InclusionAggregateProof
|
||||||
|
initialProverKeys [][]byte
|
||||||
|
head *protobufs.ClockFrame
|
||||||
|
totalDistance *big.Int
|
||||||
|
headDistance *big.Int
|
||||||
|
proverTrie *tries.RollingFrecencyCritbitTrie
|
||||||
|
pending map[uint64][]*pendingFrame
|
||||||
|
incompleteForks map[uint64][]*pendingFrame
|
||||||
|
frames chan *protobufs.ClockFrame
|
||||||
|
newFrameCh chan *protobufs.ClockFrame
|
||||||
|
badFrameCh chan *protobufs.ClockFrame
|
||||||
|
done chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDataTimeReel(
|
||||||
|
filter []byte,
|
||||||
|
logger *zap.Logger,
|
||||||
|
clockStore store.ClockStore,
|
||||||
|
engineConfig *config.EngineConfig,
|
||||||
|
frameProver crypto.FrameProver,
|
||||||
|
origin []byte,
|
||||||
|
initialInclusionProof *crypto.InclusionAggregateProof,
|
||||||
|
initialProverKeys [][]byte,
|
||||||
|
) *DataTimeReel {
|
||||||
|
if filter == nil {
|
||||||
|
panic("filter is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if logger == nil {
|
||||||
|
panic("logger is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if clockStore == nil {
|
||||||
|
panic("clock store is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if engineConfig == nil {
|
||||||
|
panic("engine config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if frameProver == nil {
|
||||||
|
panic("frame prover is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DataTimeReel{
|
||||||
|
logger: logger,
|
||||||
|
filter: filter,
|
||||||
|
engineConfig: engineConfig,
|
||||||
|
clockStore: clockStore,
|
||||||
|
frameProver: frameProver,
|
||||||
|
origin: origin,
|
||||||
|
initialInclusionProof: initialInclusionProof,
|
||||||
|
initialProverKeys: initialProverKeys,
|
||||||
|
pending: make(map[uint64][]*pendingFrame),
|
||||||
|
incompleteForks: make(map[uint64][]*pendingFrame),
|
||||||
|
frames: make(chan *protobufs.ClockFrame),
|
||||||
|
newFrameCh: make(chan *protobufs.ClockFrame),
|
||||||
|
badFrameCh: make(chan *protobufs.ClockFrame),
|
||||||
|
done: make(chan bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) Start() error {
|
||||||
|
trie := &tries.RollingFrecencyCritbitTrie{}
|
||||||
|
frame, err := d.clockStore.GetLatestDataClockFrame(d.filter, trie)
|
||||||
|
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame == nil {
|
||||||
|
d.head, d.proverTrie = d.createGenesisFrame()
|
||||||
|
d.totalDistance = big.NewInt(0)
|
||||||
|
} else {
|
||||||
|
d.head = frame
|
||||||
|
d.proverTrie = trie
|
||||||
|
d.totalDistance = d.getTotalDistance(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
go d.runLoop()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) Head() (*protobufs.ClockFrame, error) {
|
||||||
|
return d.head, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert enqueues a structurally valid frame into the time reel. If the frame
|
||||||
|
// is the next one in sequence, it advances the reel head forward and emits a
|
||||||
|
// new frame on the new frame channel.
|
||||||
|
func (d *DataTimeReel) Insert(frame *protobufs.ClockFrame) error {
|
||||||
|
go func() {
|
||||||
|
d.frames <- frame
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) GetFrameProverTrie() *tries.RollingFrecencyCritbitTrie {
|
||||||
|
return d.proverTrie
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) NewFrameCh() <-chan *protobufs.ClockFrame {
|
||||||
|
return d.newFrameCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) BadFrameCh() <-chan *protobufs.ClockFrame {
|
||||||
|
return d.badFrameCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) Stop() {
|
||||||
|
d.done <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) createGenesisFrame() (
|
||||||
|
*protobufs.ClockFrame,
|
||||||
|
*tries.RollingFrecencyCritbitTrie,
|
||||||
|
) {
|
||||||
|
if d.origin == nil {
|
||||||
|
panic("origin is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.initialInclusionProof == nil {
|
||||||
|
panic("initial inclusion proof is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.initialProverKeys == nil {
|
||||||
|
panic("initial prover keys is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
frame, trie, err := d.frameProver.CreateDataGenesisFrame(
|
||||||
|
d.filter,
|
||||||
|
d.origin,
|
||||||
|
d.engineConfig.Difficulty,
|
||||||
|
d.initialInclusionProof,
|
||||||
|
d.initialProverKeys,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
txn, err := d.clockStore.NewTransaction()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.clockStore.PutDataClockFrame(
|
||||||
|
frame,
|
||||||
|
trie,
|
||||||
|
txn,
|
||||||
|
false,
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := txn.Commit(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, trie
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main data consensus loop
|
||||||
|
func (d *DataTimeReel) runLoop() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case frame := <-d.frames:
|
||||||
|
// Most common scenario: in order – new frame is higher number
|
||||||
|
if d.head.FrameNumber < frame.FrameNumber {
|
||||||
|
parent := new(big.Int).SetBytes(frame.ParentSelector)
|
||||||
|
selector, err := frame.GetSelector()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
distance, err := d.GetDistance(frame)
|
||||||
|
if err != nil {
|
||||||
|
// If the frame arrived ahead of a master, e.g. the master data is not
|
||||||
|
// synced, we'll go ahead and mark it as pending and process it when
|
||||||
|
// we can, but if we had a general fault, panic:
|
||||||
|
if !errors.Is(err, store.ErrNotFound) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.addPending(selector, parent, unknownDistance, frame)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the frame has a gap from the head, mark it as pending:
|
||||||
|
if frame.FrameNumber-d.head.FrameNumber != 1 {
|
||||||
|
d.addPending(selector, parent, distance, frame)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise set it as the next and process all pending
|
||||||
|
d.setHead(frame, distance)
|
||||||
|
d.processPending(frame)
|
||||||
|
} else if d.head.FrameNumber == frame.FrameNumber {
|
||||||
|
// frames are equivalent, no need to act
|
||||||
|
if bytes.Equal(d.head.Output, frame.Output) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
distance, err := d.GetDistance(frame)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimization: if competing frames share a parent we can short-circuit
|
||||||
|
// fork choice
|
||||||
|
if bytes.Equal(d.head.ParentSelector, frame.ParentSelector) &&
|
||||||
|
distance.Cmp(d.headDistance) < 0 {
|
||||||
|
d.totalDistance.Sub(d.totalDistance, d.headDistance)
|
||||||
|
d.setHead(frame, distance)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose fork
|
||||||
|
d.forkChoice(frame, distance)
|
||||||
|
} else {
|
||||||
|
// tag: dusk – we should have some kind of check here to avoid brutal
|
||||||
|
// thrashing
|
||||||
|
existing, _, err := d.clockStore.GetDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
frame.FrameNumber,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
// if this returns an error it's either not found (which shouldn't
|
||||||
|
// happen without corruption) or pebble is borked, either way, panic
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's a fork, but it's behind. We need to stash it until it catches
|
||||||
|
// up (or dies off)
|
||||||
|
if !bytes.Equal(existing.Output, frame.Output) {
|
||||||
|
distance, err := d.GetDistance(frame)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parent, selector, err := frame.GetParentAndSelector()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.addPending(selector, parent, distance, frame)
|
||||||
|
d.processPending(d.head)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-d.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) addPending(
|
||||||
|
selector *big.Int,
|
||||||
|
parent *big.Int,
|
||||||
|
distance *big.Int,
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
) {
|
||||||
|
if _, ok := d.pending[frame.FrameNumber]; !ok {
|
||||||
|
d.pending[frame.FrameNumber] = []*pendingFrame{}
|
||||||
|
}
|
||||||
|
|
||||||
|
txn, err := d.clockStore.NewTransaction()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if distance.Cmp(unknownDistance) == 0 {
|
||||||
|
distance = new(big.Int).Set(unknownDistance)
|
||||||
|
distance.Sub(distance, big.NewInt(int64(len(d.pending[frame.FrameNumber]))))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = d.clockStore.PutCandidateDataClockFrame(
|
||||||
|
parent.FillBytes(make([]byte, 32)),
|
||||||
|
distance.FillBytes(make([]byte, 32)),
|
||||||
|
selector.FillBytes(make([]byte, 32)),
|
||||||
|
frame,
|
||||||
|
txn,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
txn.Abort()
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = txn.Commit(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.pending[frame.FrameNumber] = append(
|
||||||
|
d.pending[frame.FrameNumber],
|
||||||
|
&pendingFrame{
|
||||||
|
parentSelector: parent,
|
||||||
|
distance: distance,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) processPending(frame *protobufs.ClockFrame) {
|
||||||
|
neighbors := false
|
||||||
|
// Flush the current pending frames
|
||||||
|
neighborPending, ok := d.pending[frame.FrameNumber]
|
||||||
|
for ok && neighborPending != nil {
|
||||||
|
next := neighborPending[0]
|
||||||
|
d.pending[frame.FrameNumber] =
|
||||||
|
d.pending[frame.FrameNumber][1:]
|
||||||
|
if len(d.pending[frame.FrameNumber]) == 0 {
|
||||||
|
delete(d.pending, frame.FrameNumber)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFrame, err := d.clockStore.GetCandidateDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
frame.FrameNumber,
|
||||||
|
next.parentSelector.FillBytes(make([]byte, 32)),
|
||||||
|
next.distance.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if nextFrame != nil {
|
||||||
|
neighbors = true
|
||||||
|
go func() {
|
||||||
|
d.frames <- nextFrame
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
neighborPending, ok = d.pending[frame.FrameNumber]
|
||||||
|
}
|
||||||
|
|
||||||
|
if !neighbors {
|
||||||
|
// Pull the next
|
||||||
|
nextPending, ok := d.pending[frame.FrameNumber+1]
|
||||||
|
if ok {
|
||||||
|
next := nextPending[0]
|
||||||
|
d.pending[frame.FrameNumber+1] =
|
||||||
|
d.pending[frame.FrameNumber+1][1:]
|
||||||
|
if len(d.pending[frame.FrameNumber+1]) == 0 {
|
||||||
|
delete(d.pending, frame.FrameNumber+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFrame, err := d.clockStore.GetCandidateDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
frame.FrameNumber+1,
|
||||||
|
next.parentSelector.FillBytes(make([]byte, 32)),
|
||||||
|
next.distance.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if nextFrame != nil {
|
||||||
|
go func() {
|
||||||
|
d.frames <- nextFrame
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) setHead(frame *protobufs.ClockFrame, distance *big.Int) {
|
||||||
|
txn, err := d.clockStore.NewTransaction()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.clockStore.PutDataClockFrame(
|
||||||
|
frame,
|
||||||
|
d.proverTrie,
|
||||||
|
txn,
|
||||||
|
false,
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = txn.Commit(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.head = frame
|
||||||
|
d.totalDistance.Add(d.totalDistance, distance)
|
||||||
|
d.headDistance = distance
|
||||||
|
go func() {
|
||||||
|
d.newFrameCh <- frame
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag: dusk – store the distance with the frame
|
||||||
|
func (d *DataTimeReel) getTotalDistance(frame *protobufs.ClockFrame) *big.Int {
|
||||||
|
total, err := d.GetDistance(frame)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for index := frame; err == nil &&
|
||||||
|
index.FrameNumber > 0; index, err = d.clockStore.GetParentDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
index.FrameNumber-1,
|
||||||
|
index.ParentSelector,
|
||||||
|
) {
|
||||||
|
distance, err := d.GetDistance(index)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
total.Add(total, distance)
|
||||||
|
}
|
||||||
|
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) GetDistance(frame *protobufs.ClockFrame) (
|
||||||
|
*big.Int,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
// tag: equinox – master filter changes
|
||||||
|
master, err := d.clockStore.GetMasterClockFrame(
|
||||||
|
allBitmaskFilter,
|
||||||
|
frame.FrameNumber)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get distance")
|
||||||
|
}
|
||||||
|
|
||||||
|
masterSelector, err := master.GetSelector()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get distance")
|
||||||
|
}
|
||||||
|
|
||||||
|
discriminatorNode :=
|
||||||
|
d.proverTrie.FindNearest(masterSelector.FillBytes(make([]byte, 32)))
|
||||||
|
discriminator := discriminatorNode.External.Key
|
||||||
|
addr, err := frame.GetAddress()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get distance")
|
||||||
|
}
|
||||||
|
distance := new(big.Int).Sub(
|
||||||
|
new(big.Int).SetBytes(discriminator),
|
||||||
|
new(big.Int).SetBytes(addr),
|
||||||
|
)
|
||||||
|
distance.Abs(distance)
|
||||||
|
|
||||||
|
return distance, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataTimeReel) forkChoice(
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
distance *big.Int,
|
||||||
|
) {
|
||||||
|
parentSelector, selector, err := frame.GetParentAndSelector()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
leftIndex := d.head
|
||||||
|
rightIndex := frame
|
||||||
|
leftTotal := new(big.Int).Set(d.headDistance)
|
||||||
|
rightTotal := new(big.Int).Set(distance)
|
||||||
|
left := d.head.ParentSelector
|
||||||
|
right := frame.ParentSelector
|
||||||
|
|
||||||
|
rightReplaySelectors := [][]byte{selector.FillBytes(make([]byte, 32))}
|
||||||
|
|
||||||
|
// Walk backwards through the parents, until we find a matching parent
|
||||||
|
// selector:
|
||||||
|
for !bytes.Equal(left, right) {
|
||||||
|
rightReplaySelectors = append(
|
||||||
|
append(
|
||||||
|
[][]byte{},
|
||||||
|
right,
|
||||||
|
),
|
||||||
|
rightReplaySelectors...,
|
||||||
|
)
|
||||||
|
leftIndex, err = d.clockStore.GetParentDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
leftIndex.FrameNumber-1,
|
||||||
|
leftIndex.ParentSelector,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rightIndex, err = d.clockStore.GetParentDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
rightIndex.FrameNumber-1,
|
||||||
|
rightIndex.ParentSelector,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
// If lineage cannot be verified, set it for later
|
||||||
|
if errors.Is(err, store.ErrNotFound) {
|
||||||
|
d.addPending(selector, parentSelector, distance, frame)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
left = leftIndex.ParentSelector
|
||||||
|
right = rightIndex.ParentSelector
|
||||||
|
leftIndexDistance, err := d.GetDistance(leftIndex)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rightIndexDistance, err := d.GetDistance(rightIndex)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
leftTotal.Add(leftTotal, leftIndexDistance)
|
||||||
|
rightTotal.Add(rightTotal, rightIndexDistance)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose new fork based on lightest distance sub-tree
|
||||||
|
if rightTotal.Cmp(leftTotal) < 0 {
|
||||||
|
for {
|
||||||
|
if len(rightReplaySelectors) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
next := rightReplaySelectors[0]
|
||||||
|
rightReplaySelectors[frame.FrameNumber] =
|
||||||
|
rightReplaySelectors[frame.FrameNumber][1:]
|
||||||
|
|
||||||
|
rightIndex, err = d.clockStore.GetParentDataClockFrame(
|
||||||
|
d.filter,
|
||||||
|
rightIndex.FrameNumber+1,
|
||||||
|
next,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
txn, err := d.clockStore.NewTransaction()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.clockStore.PutDataClockFrame(
|
||||||
|
rightIndex,
|
||||||
|
d.proverTrie,
|
||||||
|
txn,
|
||||||
|
false,
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = txn.Commit(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.head = frame
|
||||||
|
d.totalDistance.Sub(d.totalDistance, leftTotal)
|
||||||
|
d.totalDistance.Add(d.totalDistance, rightTotal)
|
||||||
|
d.headDistance = distance
|
||||||
|
go func() {
|
||||||
|
d.newFrameCh <- frame
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ TimeReel = (*DataTimeReel)(nil)
|
407
node/consensus/time/data_time_reel_test.go
Normal file
407
node/consensus/time/data_time_reel_test.go
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
package time_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cloudflare/circl/sign/ed448"
|
||||||
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
|
"github.com/libp2p/go-libp2p/core/crypto"
|
||||||
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
|
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateTestProvers() (
|
||||||
|
keys.KeyManager,
|
||||||
|
[]peer.ID,
|
||||||
|
[][]byte,
|
||||||
|
[][]byte,
|
||||||
|
map[string]string,
|
||||||
|
*tries.RollingFrecencyCritbitTrie,
|
||||||
|
) {
|
||||||
|
keyManager := keys.NewInMemoryKeyManager()
|
||||||
|
peers := []peer.ID{}
|
||||||
|
pubKeys := [][]byte{}
|
||||||
|
privKeys := [][]byte{}
|
||||||
|
addrMap := map[string]string{}
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
keyManager.CreateSigningKey(
|
||||||
|
fmt.Sprintf("test-key-%d", i),
|
||||||
|
keys.KeyTypeEd448,
|
||||||
|
)
|
||||||
|
k, err := keyManager.GetRawKey(fmt.Sprintf("test-key-%d", i))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey, err := crypto.UnmarshalEd448PrivateKey([]byte(k.PrivateKey))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
privKeys = append(privKeys, []byte(k.PrivateKey))
|
||||||
|
|
||||||
|
pub := privKey.GetPublic()
|
||||||
|
id, err := peer.IDFromPublicKey(pub)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peers = append(peers, id)
|
||||||
|
|
||||||
|
keyManager.CreateSigningKey(
|
||||||
|
fmt.Sprintf("proving-key-%d", i),
|
||||||
|
keys.KeyTypeEd448,
|
||||||
|
)
|
||||||
|
pk, err := keyManager.GetRawKey(fmt.Sprintf("proving-key-%d", i))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pprivKey, err := crypto.UnmarshalEd448PrivateKey([]byte(pk.PrivateKey))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ppub := pprivKey.GetPublic()
|
||||||
|
ppubKey, err := ppub.Raw()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKeys = append(pubKeys, ppubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
proverTrie := &tries.RollingFrecencyCritbitTrie{}
|
||||||
|
|
||||||
|
for i, s := range pubKeys {
|
||||||
|
addr, err := poseidon.HashBytes(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrBytes := addr.Bytes()
|
||||||
|
addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...)
|
||||||
|
proverTrie.Add(addrBytes, 0)
|
||||||
|
addrMap[string(addrBytes)] = fmt.Sprintf("proving-key-%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyManager,
|
||||||
|
peers,
|
||||||
|
pubKeys,
|
||||||
|
privKeys,
|
||||||
|
addrMap,
|
||||||
|
proverTrie
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDataTimeReel(t *testing.T) {
|
||||||
|
logger, _ := zap.NewProduction()
|
||||||
|
db := store.NewInMemKVDB()
|
||||||
|
clockStore := store.NewPebbleClockStore(db, logger)
|
||||||
|
prover := qcrypto.NewWesolowskiFrameProver(logger)
|
||||||
|
filter := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||||
|
keyManager,
|
||||||
|
_,
|
||||||
|
pubKeys,
|
||||||
|
_,
|
||||||
|
addrMap,
|
||||||
|
proverTrie := generateTestProvers()
|
||||||
|
|
||||||
|
// We're going to set this up by churning 100 master frames so we don't
|
||||||
|
// have to zig zag on master and data frames to confirm data time reel
|
||||||
|
// behaviors
|
||||||
|
m := time.NewMasterTimeReel(
|
||||||
|
logger,
|
||||||
|
clockStore,
|
||||||
|
&config.EngineConfig{
|
||||||
|
Filter: filter,
|
||||||
|
GenesisSeed: strings.Repeat("00", 516),
|
||||||
|
Difficulty: 10,
|
||||||
|
},
|
||||||
|
prover,
|
||||||
|
)
|
||||||
|
|
||||||
|
err := m.Start()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
frame, err := m.Head()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
frames := []*protobufs.ClockFrame{}
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
frameCh := m.NewFrameCh()
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
frames = append(frames, <-frameCh)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// in order
|
||||||
|
for i := int64(0); i < 100; i++ {
|
||||||
|
frame, err = prover.ProveMasterClockFrame(frame, i+1, 10)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err := m.Insert(frame)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
assert.NotNil(t, frames[i])
|
||||||
|
assert.Equal(t, frames[i].FrameNumber, uint64(i+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
filterBytes, _ := hex.DecodeString(filter)
|
||||||
|
|
||||||
|
// Ok, now onto the data time reel. We're going to test the following
|
||||||
|
// scenarios:
|
||||||
|
// 1. Z-dist optimal, in order
|
||||||
|
// 2. Z-dist optimal, out of order
|
||||||
|
// 3. 90% optimal, out of order
|
||||||
|
// 4. Malicious majority, out of order
|
||||||
|
d := time.NewDataTimeReel(
|
||||||
|
filterBytes,
|
||||||
|
logger,
|
||||||
|
clockStore,
|
||||||
|
&config.EngineConfig{
|
||||||
|
Filter: filter,
|
||||||
|
GenesisSeed: strings.Repeat("00", 516),
|
||||||
|
Difficulty: 10,
|
||||||
|
},
|
||||||
|
prover,
|
||||||
|
frames[0].Output,
|
||||||
|
&qcrypto.InclusionAggregateProof{
|
||||||
|
InclusionCommitments: []*qcrypto.InclusionCommitment{},
|
||||||
|
AggregateCommitment: []byte{},
|
||||||
|
Proof: []byte{},
|
||||||
|
},
|
||||||
|
pubKeys,
|
||||||
|
)
|
||||||
|
|
||||||
|
err = d.Start()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
frame, err = d.Head()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
dataFrames := []*protobufs.ClockFrame{}
|
||||||
|
datawg := sync.WaitGroup{}
|
||||||
|
datawg.Add(1)
|
||||||
|
dataFrameCh := d.NewFrameCh()
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 40; i++ {
|
||||||
|
dataFrames = append(dataFrames, <-dataFrameCh)
|
||||||
|
}
|
||||||
|
datawg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 1. z-dist optimal – proof submission is strictly master-frame evoked leader
|
||||||
|
for i := int64(0); i < 10; i++ {
|
||||||
|
masterSelector, err := frames[i+1].GetSelector()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proverSelection := proverTrie.FindNearest(
|
||||||
|
masterSelector.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
optimalSigner, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelection.External.Key)],
|
||||||
|
)
|
||||||
|
frame, err = prover.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
optimalSigner,
|
||||||
|
i+1,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
d.Insert(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. z-dist optimal, out of order – proof submission is strictly master-frame
|
||||||
|
// evoked leader, but arrived completely backwards
|
||||||
|
insertFrames := []*protobufs.ClockFrame{}
|
||||||
|
|
||||||
|
for i := int64(10); i < 20; i++ {
|
||||||
|
masterSelector, err := frames[i+1].GetSelector()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proverSelection := proverTrie.FindNearest(
|
||||||
|
masterSelector.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
optimalSigner, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelection.External.Key)],
|
||||||
|
)
|
||||||
|
frame, err = prover.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
optimalSigner,
|
||||||
|
i+1,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
insertFrames = append(insertFrames, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 9; i >= 0; i-- {
|
||||||
|
err := d.Insert(insertFrames[i])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 90% optimal, out of order
|
||||||
|
insertFrames = []*protobufs.ClockFrame{}
|
||||||
|
|
||||||
|
for i := int64(20); i < 25; i++ {
|
||||||
|
masterSelector, err := frames[i+1].GetSelector()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proverSelection := proverTrie.FindNearest(
|
||||||
|
masterSelector.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
optimalSigner, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelection.External.Key)],
|
||||||
|
)
|
||||||
|
frame, err = prover.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
optimalSigner,
|
||||||
|
i+1,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
d.Insert(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
masterSelector, err := frames[26].GetSelector()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proverSelections := proverTrie.FindNearestAndApproximateNeighbors(
|
||||||
|
masterSelector.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
suboptimalSigner2, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelections[2].External.Key)],
|
||||||
|
)
|
||||||
|
// What we're trying to simulate: consensus heads progressed on a slightly
|
||||||
|
// less optimal prover.
|
||||||
|
frame, err = prover.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
suboptimalSigner2,
|
||||||
|
26,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
insertFrames = append(insertFrames, frame)
|
||||||
|
|
||||||
|
for i := int64(26); i < 30; i++ {
|
||||||
|
masterSelector, err := frames[i+1].GetSelector()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proverSelection := proverTrie.FindNearest(
|
||||||
|
masterSelector.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
optimalSigner, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelection.External.Key)],
|
||||||
|
)
|
||||||
|
frame, err = prover.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
optimalSigner,
|
||||||
|
i+1,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
insertFrames = append(insertFrames, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 4; i >= 0; i-- {
|
||||||
|
err := d.Insert(insertFrames[i])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Malicious majority, out of order – handle a suppressive majority and
|
||||||
|
// force consensus on the lowest distance sub-tree:
|
||||||
|
insertFrames = []*protobufs.ClockFrame{}
|
||||||
|
conflictFrames := []*protobufs.ClockFrame{}
|
||||||
|
optimalKeySet := [][]byte{}
|
||||||
|
suppressedFrame := frame
|
||||||
|
for i := int64(30); i < 40; i++ {
|
||||||
|
masterSelector, err := frames[i+1].GetSelector()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proverSelections := proverTrie.FindNearestAndApproximateNeighbors(
|
||||||
|
masterSelector.FillBytes(make([]byte, 32)),
|
||||||
|
)
|
||||||
|
optimalSigner, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelections[0].External.Key)],
|
||||||
|
)
|
||||||
|
suboptimalSigner2, _ := keyManager.GetSigningKey(
|
||||||
|
addrMap[string(proverSelections[2].External.Key)],
|
||||||
|
)
|
||||||
|
optimalKeySet = append(optimalKeySet, []byte(
|
||||||
|
(optimalSigner.Public()).(ed448.PublicKey),
|
||||||
|
))
|
||||||
|
|
||||||
|
// What we're trying to simulate: the majority is intentionally ignoring
|
||||||
|
// the most optimal signer
|
||||||
|
suppressedFrame, err := prover.ProveDataClockFrame(
|
||||||
|
suppressedFrame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
optimalSigner,
|
||||||
|
i+1,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
insertFrames = append(insertFrames, suppressedFrame)
|
||||||
|
frame, err = prover.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{},
|
||||||
|
[]*protobufs.InclusionAggregateProof{},
|
||||||
|
suboptimalSigner2,
|
||||||
|
i+1,
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
conflictFrames = append(conflictFrames, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 9; i >= 0; i-- {
|
||||||
|
err := d.Insert(conflictFrames[i])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Someone is honest, but clumsy:
|
||||||
|
for i := 9; i >= 0; i-- {
|
||||||
|
err := d.Insert(insertFrames[i])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
datawg.Wait()
|
||||||
|
|
||||||
|
for i := 0; i < 40; i++ {
|
||||||
|
assert.NotNil(t, dataFrames[i])
|
||||||
|
|
||||||
|
if i >= 40 {
|
||||||
|
assert.Equal(t, uint64(i), dataFrames[i].FrameNumber)
|
||||||
|
assert.Equal(
|
||||||
|
t,
|
||||||
|
dataFrames[i].GetPublicKeySignatureEd448().PublicKey.KeyValue,
|
||||||
|
optimalKeySet[i-30],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, uint64(i+1), dataFrames[i].FrameNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
221
node/consensus/time/master_time_reel.go
Normal file
221
node/consensus/time/master_time_reel.go
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MasterTimeReel struct {
|
||||||
|
rwMutex sync.RWMutex
|
||||||
|
|
||||||
|
filter []byte
|
||||||
|
engineConfig *config.EngineConfig
|
||||||
|
logger *zap.Logger
|
||||||
|
clockStore store.ClockStore
|
||||||
|
frameProver crypto.FrameProver
|
||||||
|
|
||||||
|
head *protobufs.ClockFrame
|
||||||
|
pending map[uint64][]*big.Int
|
||||||
|
frames chan *protobufs.ClockFrame
|
||||||
|
newFrameCh chan *protobufs.ClockFrame
|
||||||
|
badFrameCh chan *protobufs.ClockFrame
|
||||||
|
done chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMasterTimeReel(
|
||||||
|
logger *zap.Logger,
|
||||||
|
clockStore store.ClockStore,
|
||||||
|
engineConfig *config.EngineConfig,
|
||||||
|
frameProver crypto.FrameProver,
|
||||||
|
) *MasterTimeReel {
|
||||||
|
if logger == nil {
|
||||||
|
panic("logger is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if clockStore == nil {
|
||||||
|
panic("clock store is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if engineConfig == nil {
|
||||||
|
panic("engine config is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if frameProver == nil {
|
||||||
|
panic("frame prover is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
filter, err := hex.DecodeString(engineConfig.Filter)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MasterTimeReel{
|
||||||
|
logger: logger,
|
||||||
|
filter: filter,
|
||||||
|
engineConfig: engineConfig,
|
||||||
|
clockStore: clockStore,
|
||||||
|
frameProver: frameProver,
|
||||||
|
pending: make(map[uint64][]*big.Int),
|
||||||
|
frames: make(chan *protobufs.ClockFrame),
|
||||||
|
newFrameCh: make(chan *protobufs.ClockFrame),
|
||||||
|
badFrameCh: make(chan *protobufs.ClockFrame),
|
||||||
|
done: make(chan bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start implements TimeReel.
|
||||||
|
func (m *MasterTimeReel) Start() error {
|
||||||
|
frame, err := m.clockStore.GetLatestMasterClockFrame(m.filter)
|
||||||
|
if err != nil && !errors.Is(err, store.ErrNotFound) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame == nil {
|
||||||
|
m.head = m.createGenesisFrame()
|
||||||
|
} else {
|
||||||
|
m.head = frame
|
||||||
|
}
|
||||||
|
|
||||||
|
go m.runLoop()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head implements TimeReel.
|
||||||
|
func (m *MasterTimeReel) Head() (*protobufs.ClockFrame, error) {
|
||||||
|
return m.head, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert enqueues a structurally valid frame into the time reel. If the frame
|
||||||
|
// is the next one in sequence, it advances the reel head forward and emits a
|
||||||
|
// new frame on the new frame channel.
|
||||||
|
func (m *MasterTimeReel) Insert(frame *protobufs.ClockFrame) error {
|
||||||
|
go func() {
|
||||||
|
m.frames <- frame
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFrameCh implements TimeReel.
|
||||||
|
func (m *MasterTimeReel) NewFrameCh() <-chan *protobufs.ClockFrame {
|
||||||
|
return m.newFrameCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MasterTimeReel) BadFrameCh() <-chan *protobufs.ClockFrame {
|
||||||
|
return m.badFrameCh
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop implements TimeReel.
|
||||||
|
func (m *MasterTimeReel) Stop() {
|
||||||
|
m.done <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MasterTimeReel) createGenesisFrame() *protobufs.ClockFrame {
|
||||||
|
seed, err := hex.DecodeString(m.engineConfig.GenesisSeed)
|
||||||
|
if err != nil {
|
||||||
|
panic(errors.New("genesis seed is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
|
frame, err := m.frameProver.CreateMasterGenesisFrame(
|
||||||
|
m.filter,
|
||||||
|
seed,
|
||||||
|
m.engineConfig.Difficulty,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
txn, err := m.clockStore.NewTransaction()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = m.clockStore.PutMasterClockFrame(frame, txn); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = txn.Commit(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MasterTimeReel) runLoop() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case frame := <-m.frames:
|
||||||
|
if m.head.FrameNumber < frame.FrameNumber {
|
||||||
|
m.logger.Debug(
|
||||||
|
"new frame has higher number",
|
||||||
|
zap.Uint32("new_frame_number", uint32(frame.FrameNumber)),
|
||||||
|
zap.Uint32("frame_number", uint32(m.head.FrameNumber)),
|
||||||
|
)
|
||||||
|
if frame.FrameNumber-m.head.FrameNumber == 1 {
|
||||||
|
parent := new(big.Int).SetBytes(frame.ParentSelector)
|
||||||
|
selector, err := m.head.GetSelector()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// master frames cannot fork, this is invalid
|
||||||
|
if parent.Cmp(selector) != 0 {
|
||||||
|
m.logger.Debug(
|
||||||
|
"invalid parent selector for frame",
|
||||||
|
zap.Binary("frame_parent_selector", frame.ParentSelector),
|
||||||
|
zap.Binary("actual_parent_selector", selector.FillBytes(
|
||||||
|
make([]byte, 32),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
go func() {
|
||||||
|
m.badFrameCh <- frame
|
||||||
|
}()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
txn, err := m.clockStore.NewTransaction()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.clockStore.PutMasterClockFrame(frame, txn); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = txn.Commit(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.head = frame
|
||||||
|
go func() {
|
||||||
|
m.newFrameCh <- frame
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
m.frames <- frame
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m.logger.Debug(
|
||||||
|
"new frame has same or lower frame number",
|
||||||
|
zap.Uint32("new_frame_number", uint32(frame.FrameNumber)),
|
||||||
|
zap.Uint32("frame_number", uint32(m.head.FrameNumber)),
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case <-m.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ TimeReel = (*MasterTimeReel)(nil)
|
82
node/consensus/time/master_time_reel_test.go
Normal file
82
node/consensus/time/master_time_reel_test.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package time_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMasterTimeReel(t *testing.T) {
|
||||||
|
logger, _ := zap.NewProduction()
|
||||||
|
db := store.NewInMemKVDB()
|
||||||
|
clockStore := store.NewPebbleClockStore(db, logger)
|
||||||
|
prover := crypto.NewWesolowskiFrameProver(logger)
|
||||||
|
filter := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||||
|
|
||||||
|
m := time.NewMasterTimeReel(
|
||||||
|
logger,
|
||||||
|
clockStore,
|
||||||
|
&config.EngineConfig{
|
||||||
|
Filter: filter,
|
||||||
|
GenesisSeed: strings.Repeat("00", 516),
|
||||||
|
Difficulty: 10,
|
||||||
|
},
|
||||||
|
prover,
|
||||||
|
)
|
||||||
|
|
||||||
|
err := m.Start()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
frame, err := m.Head()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
frames := []*protobufs.ClockFrame{}
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
frameCh := m.NewFrameCh()
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
frames = append(frames, <-frameCh)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// in order
|
||||||
|
for i := int64(0); i < 100; i++ {
|
||||||
|
frame, err = prover.ProveMasterClockFrame(frame, i+1, 10)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err := m.Insert(frame)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
insertFrames := []*protobufs.ClockFrame{}
|
||||||
|
|
||||||
|
// reverse order
|
||||||
|
for i := int64(100); i < 200; i++ {
|
||||||
|
frame, err = prover.ProveMasterClockFrame(frame, i+1, 10)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
insertFrames = append(insertFrames, frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 99; i >= 0; i-- {
|
||||||
|
err := m.Insert(insertFrames[i])
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
for i := 0; i < 200; i++ {
|
||||||
|
assert.NotNil(t, frames[i])
|
||||||
|
assert.Equal(t, frames[i].FrameNumber, uint64(i+1))
|
||||||
|
}
|
||||||
|
}
|
14
node/consensus/time/time_reel.go
Normal file
14
node/consensus/time/time_reel.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package time
|
||||||
|
|
||||||
|
import (
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TimeReel interface {
|
||||||
|
Start() error
|
||||||
|
Stop()
|
||||||
|
Insert(frame *protobufs.ClockFrame) error
|
||||||
|
Head() (*protobufs.ClockFrame, error)
|
||||||
|
NewFrameCh() <-chan *protobufs.ClockFrame
|
||||||
|
BadFrameCh() <-chan *protobufs.ClockFrame
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package crypto
|
package channel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
@ -1,4 +1,4 @@
|
|||||||
package crypto_test
|
package channel_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/channel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRatchetEncrypt(t *testing.T) {
|
func TestRatchetEncrypt(t *testing.T) {
|
||||||
@ -20,7 +20,7 @@ func TestRatchetEncrypt(t *testing.T) {
|
|||||||
x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey)
|
x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey)
|
||||||
x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey)
|
x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey)
|
||||||
|
|
||||||
senderResult := crypto.SenderX3DH(
|
senderResult := channel.SenderX3DH(
|
||||||
x448SendingIdentityPrivateKey,
|
x448SendingIdentityPrivateKey,
|
||||||
x448SendingEphemeralPrivateKey,
|
x448SendingEphemeralPrivateKey,
|
||||||
x448ReceivingIdentityKey,
|
x448ReceivingIdentityKey,
|
||||||
@ -28,7 +28,7 @@ func TestRatchetEncrypt(t *testing.T) {
|
|||||||
96,
|
96,
|
||||||
)
|
)
|
||||||
|
|
||||||
receiverResult := crypto.ReceiverX3DH(
|
receiverResult := channel.ReceiverX3DH(
|
||||||
x448ReceivingIdentityPrivateKey,
|
x448ReceivingIdentityPrivateKey,
|
||||||
x448ReceivingSignedPrePrivateKey,
|
x448ReceivingSignedPrePrivateKey,
|
||||||
x448SendingIdentityKey,
|
x448SendingIdentityKey,
|
||||||
@ -36,7 +36,7 @@ func TestRatchetEncrypt(t *testing.T) {
|
|||||||
96,
|
96,
|
||||||
)
|
)
|
||||||
|
|
||||||
sender, err := crypto.NewDoubleRatchetParticipant(
|
sender, err := channel.NewDoubleRatchetParticipant(
|
||||||
senderResult[:32],
|
senderResult[:32],
|
||||||
senderResult[32:64],
|
senderResult[32:64],
|
||||||
senderResult[64:],
|
senderResult[64:],
|
||||||
@ -48,7 +48,7 @@ func TestRatchetEncrypt(t *testing.T) {
|
|||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
receiver, err := crypto.NewDoubleRatchetParticipant(
|
receiver, err := channel.NewDoubleRatchetParticipant(
|
||||||
receiverResult[:32],
|
receiverResult[:32],
|
||||||
receiverResult[32:64],
|
receiverResult[32:64],
|
||||||
receiverResult[64:],
|
receiverResult[64:],
|
@ -1,4 +1,4 @@
|
|||||||
package crypto
|
package channel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
@ -1,4 +1,4 @@
|
|||||||
package crypto_test
|
package channel_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/channel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestX3DHMatches(t *testing.T) {
|
func TestX3DHMatches(t *testing.T) {
|
||||||
@ -20,7 +20,7 @@ func TestX3DHMatches(t *testing.T) {
|
|||||||
x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey)
|
x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey)
|
||||||
x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey)
|
x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey)
|
||||||
|
|
||||||
result := crypto.SenderX3DH(
|
result := channel.SenderX3DH(
|
||||||
x448SendingIdentityPrivateKey,
|
x448SendingIdentityPrivateKey,
|
||||||
x448SendingEphemeralPrivateKey,
|
x448SendingEphemeralPrivateKey,
|
||||||
x448ReceivingIdentityKey,
|
x448ReceivingIdentityKey,
|
||||||
@ -28,7 +28,7 @@ func TestX3DHMatches(t *testing.T) {
|
|||||||
32,
|
32,
|
||||||
)
|
)
|
||||||
|
|
||||||
compare := crypto.ReceiverX3DH(
|
compare := channel.ReceiverX3DH(
|
||||||
x448ReceivingIdentityPrivateKey,
|
x448ReceivingIdentityPrivateKey,
|
||||||
x448ReceivingSignedPrePrivateKey,
|
x448ReceivingSignedPrePrivateKey,
|
||||||
x448SendingIdentityKey,
|
x448SendingIdentityKey,
|
43
node/crypto/frame_prover.go
Normal file
43
node/crypto/frame_prover.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FrameProver interface {
|
||||||
|
ProveMasterClockFrame(
|
||||||
|
previousFrame *protobufs.ClockFrame,
|
||||||
|
timestamp int64,
|
||||||
|
difficulty uint32,
|
||||||
|
) (*protobufs.ClockFrame, error)
|
||||||
|
ProveDataClockFrame(
|
||||||
|
previousFrame *protobufs.ClockFrame,
|
||||||
|
commitments [][]byte,
|
||||||
|
aggregateProofs []*protobufs.InclusionAggregateProof,
|
||||||
|
provingKey crypto.Signer,
|
||||||
|
timestamp int64,
|
||||||
|
difficulty uint32,
|
||||||
|
) (*protobufs.ClockFrame, error)
|
||||||
|
CreateMasterGenesisFrame(
|
||||||
|
filter []byte,
|
||||||
|
seed []byte,
|
||||||
|
difficulty uint32,
|
||||||
|
) (*protobufs.ClockFrame, error)
|
||||||
|
CreateDataGenesisFrame(
|
||||||
|
filter []byte,
|
||||||
|
origin []byte,
|
||||||
|
difficulty uint32,
|
||||||
|
inclusionProof *InclusionAggregateProof,
|
||||||
|
proverKeys [][]byte,
|
||||||
|
preDusk bool,
|
||||||
|
) (*protobufs.ClockFrame, *tries.RollingFrecencyCritbitTrie, error)
|
||||||
|
VerifyMasterClockFrame(
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
) error
|
||||||
|
VerifyDataClockFrame(
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
) error
|
||||||
|
}
|
28
node/crypto/inclusion_prover.go
Normal file
28
node/crypto/inclusion_prover.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import "source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
|
||||||
|
type InclusionCommitment struct {
|
||||||
|
TypeUrl string
|
||||||
|
Data []byte
|
||||||
|
Commitment []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type InclusionAggregateProof struct {
|
||||||
|
InclusionCommitments []*InclusionCommitment
|
||||||
|
AggregateCommitment []byte
|
||||||
|
Proof []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type InclusionProver interface {
|
||||||
|
Commit(
|
||||||
|
data []byte,
|
||||||
|
typeUrl string,
|
||||||
|
) (*InclusionCommitment, error)
|
||||||
|
ProveAggregate(commits []*InclusionCommitment) (
|
||||||
|
*InclusionAggregateProof,
|
||||||
|
error,
|
||||||
|
)
|
||||||
|
VerifyAggregate(proof *InclusionAggregateProof) (bool, error)
|
||||||
|
VerifyFrame(frame *protobufs.ClockFrame) error
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package crypto
|
package kzg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
@ -1,4 +1,4 @@
|
|||||||
package crypto
|
package kzg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
@ -1,4 +1,4 @@
|
|||||||
package crypto_test
|
package kzg_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
@ -13,16 +13,16 @@ import (
|
|||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/kzg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
csBytes, err := os.ReadFile("../ceremony.json")
|
csBytes, err := os.ReadFile("../../ceremony.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cs := &crypto.CeremonyState{}
|
cs := &kzg.CeremonyState{}
|
||||||
if err := json.Unmarshal(csBytes, cs); err != nil {
|
if err := json.Unmarshal(csBytes, cs); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -75,8 +75,8 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
crypto.CeremonyBLS48581G1 = g1s
|
kzg.CeremonyBLS48581G1 = g1s
|
||||||
crypto.CeremonyBLS48581G2 = g2s
|
kzg.CeremonyBLS48581G2 = g2s
|
||||||
|
|
||||||
// Post-ceremony, precompute everything and put it in the finalized ceremony
|
// Post-ceremony, precompute everything and put it in the finalized ceremony
|
||||||
// state
|
// state
|
||||||
@ -135,16 +135,16 @@ func TestMain(m *testing.M) {
|
|||||||
wg.Add(len(sizes))
|
wg.Add(len(sizes))
|
||||||
for i := range root {
|
for i := range root {
|
||||||
i := i
|
i := i
|
||||||
crypto.RootOfUnityBLS48581[uint64(sizes[i])] = root[i]
|
kzg.RootOfUnityBLS48581[uint64(sizes[i])] = root[i]
|
||||||
crypto.RootsOfUnityBLS48581[uint64(sizes[i])] = roots[i]
|
kzg.RootsOfUnityBLS48581[uint64(sizes[i])] = roots[i]
|
||||||
crypto.ReverseRootsOfUnityBLS48581[uint64(sizes[i])] = reverseRoots[i]
|
kzg.ReverseRootsOfUnityBLS48581[uint64(sizes[i])] = reverseRoots[i]
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// We precomputed 65536, others are cheap and will be fully precomputed
|
// We precomputed 65536, others are cheap and will be fully precomputed
|
||||||
// post-ceremony
|
// post-ceremony
|
||||||
if sizes[i] < 65536 {
|
if sizes[i] < 65536 {
|
||||||
fftG1, err := crypto.FFTG1(
|
fftG1, err := kzg.FFTG1(
|
||||||
crypto.CeremonyBLS48581G1[:sizes[i]],
|
kzg.CeremonyBLS48581G1[:sizes[i]],
|
||||||
*curves.BLS48581(
|
*curves.BLS48581(
|
||||||
curves.BLS48581G1().NewGeneratorPoint(),
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
),
|
),
|
||||||
@ -165,7 +165,7 @@ func TestMain(m *testing.M) {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
for i := range root {
|
for i := range root {
|
||||||
crypto.FFTBLS48581[uint64(sizes[i])] = ffts[i]
|
kzg.FFTBLS48581[uint64(sizes[i])] = ffts[i]
|
||||||
}
|
}
|
||||||
code := m.Run()
|
code := m.Run()
|
||||||
os.Exit(code)
|
os.Exit(code)
|
||||||
@ -175,7 +175,7 @@ func TestKzgBytesToPoly(t *testing.T) {
|
|||||||
modulus := make([]byte, 73)
|
modulus := make([]byte, 73)
|
||||||
bls48581.NewBIGints(bls48581.CURVE_Order, nil).ToBytes(modulus)
|
bls48581.NewBIGints(bls48581.CURVE_Order, nil).ToBytes(modulus)
|
||||||
q := new(big.Int).SetBytes(modulus)
|
q := new(big.Int).SetBytes(modulus)
|
||||||
p := crypto.NewKZGProver(curves.BLS48581(curves.BLS48581G1().Point), sha3.New256, q)
|
p := kzg.NewKZGProver(curves.BLS48581(curves.BLS48581G1().Point), sha3.New256, q)
|
||||||
|
|
||||||
poly, err := p.BytesToPolynomial([]byte(
|
poly, err := p.BytesToPolynomial([]byte(
|
||||||
"Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not." +
|
"Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not." +
|
||||||
@ -217,7 +217,7 @@ func TestPolynomialCommitment(t *testing.T) {
|
|||||||
modulus := make([]byte, 73)
|
modulus := make([]byte, 73)
|
||||||
bls48581.NewBIGints(bls48581.CURVE_Order, nil).ToBytes(modulus)
|
bls48581.NewBIGints(bls48581.CURVE_Order, nil).ToBytes(modulus)
|
||||||
q := new(big.Int).SetBytes(modulus)
|
q := new(big.Int).SetBytes(modulus)
|
||||||
p := crypto.NewKZGProver(curves.BLS48581(curves.BLS48581G1().Point), sha3.New256, q)
|
p := kzg.NewKZGProver(curves.BLS48581(curves.BLS48581G1().Point), sha3.New256, q)
|
||||||
|
|
||||||
poly, err := p.BytesToPolynomial([]byte(
|
poly, err := p.BytesToPolynomial([]byte(
|
||||||
"Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not." +
|
"Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not." +
|
||||||
@ -235,7 +235,7 @@ func TestPolynomialCommitment(t *testing.T) {
|
|||||||
poly = append(poly, curves.BLS48581G1().NewScalar().(curves.PairingScalar))
|
poly = append(poly, curves.BLS48581G1().NewScalar().(curves.PairingScalar))
|
||||||
}
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
evalPoly, err := crypto.FFT(
|
evalPoly, err := kzg.FFT(
|
||||||
poly,
|
poly,
|
||||||
*curves.BLS48581(
|
*curves.BLS48581(
|
||||||
curves.BLS48581G1().NewGeneratorPoint(),
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
@ -247,12 +247,12 @@ func TestPolynomialCommitment(t *testing.T) {
|
|||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
commitByCoeffs, err := p.PointLinearCombination(
|
commitByCoeffs, err := p.PointLinearCombination(
|
||||||
crypto.CeremonyBLS48581G1[:16],
|
kzg.CeremonyBLS48581G1[:16],
|
||||||
poly,
|
poly,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
commitByEval, err := p.PointLinearCombination(
|
commitByEval, err := p.PointLinearCombination(
|
||||||
crypto.FFTBLS48581[16],
|
kzg.FFTBLS48581[16],
|
||||||
evalPoly,
|
evalPoly,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -265,7 +265,7 @@ func TestKZGProof(t *testing.T) {
|
|||||||
modulus := make([]byte, 73)
|
modulus := make([]byte, 73)
|
||||||
bls48581.NewBIGints(bls48581.CURVE_Order, nil).ToBytes(modulus)
|
bls48581.NewBIGints(bls48581.CURVE_Order, nil).ToBytes(modulus)
|
||||||
q := new(big.Int).SetBytes(modulus)
|
q := new(big.Int).SetBytes(modulus)
|
||||||
p := crypto.NewKZGProver(curves.BLS48581(curves.BLS48581G1().Point), sha3.New256, q)
|
p := kzg.NewKZGProver(curves.BLS48581(curves.BLS48581G1().Point), sha3.New256, q)
|
||||||
|
|
||||||
poly, err := p.BytesToPolynomial([]byte(
|
poly, err := p.BytesToPolynomial([]byte(
|
||||||
"Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not." +
|
"Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not." +
|
||||||
@ -284,7 +284,7 @@ func TestKZGProof(t *testing.T) {
|
|||||||
poly = append(poly, curves.BLS48581G1().NewScalar().(curves.PairingScalar))
|
poly = append(poly, curves.BLS48581G1().NewScalar().(curves.PairingScalar))
|
||||||
}
|
}
|
||||||
|
|
||||||
evalPoly, err := crypto.FFT(
|
evalPoly, err := kzg.FFT(
|
||||||
poly,
|
poly,
|
||||||
*curves.BLS48581(
|
*curves.BLS48581(
|
||||||
curves.BLS48581G1().NewGeneratorPoint(),
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
@ -297,7 +297,7 @@ func TestKZGProof(t *testing.T) {
|
|||||||
commit, err := p.Commit(poly)
|
commit, err := p.Commit(poly)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
z := crypto.RootsOfUnityBLS48581[16][2]
|
z := kzg.RootsOfUnityBLS48581[16][2]
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
checky := evalPoly[len(poly)-1]
|
checky := evalPoly[len(poly)-1]
|
||||||
@ -331,7 +331,7 @@ func TestKZGProof(t *testing.T) {
|
|||||||
diff -= 1
|
diff -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
proof, err := p.PointLinearCombination(crypto.CeremonyBLS48581G1[:15], out)
|
proof, err := p.PointLinearCombination(kzg.CeremonyBLS48581G1[:15], out)
|
||||||
// proof, err := p.Prove(evalPoly, commit, z.(curves.PairingScalar))
|
// proof, err := p.Prove(evalPoly, commit, z.(curves.PairingScalar))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, p.Verify(commit, z, checky, proof))
|
require.True(t, p.Verify(commit, z, checky, proof))
|
464
node/crypto/kzg_inclusion_prover.go
Normal file
464
node/crypto/kzg_inclusion_prover.go
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/kzg"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KZGInclusionProver struct {
|
||||||
|
prover *kzg.KZGProver
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKZGInclusionProver(logger *zap.Logger) *KZGInclusionProver {
|
||||||
|
return &KZGInclusionProver{
|
||||||
|
prover: kzg.DefaultKZGProver(),
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit implements InclusionProver.
|
||||||
|
func (k *KZGInclusionProver) Commit(
|
||||||
|
data []byte,
|
||||||
|
typeUrl string,
|
||||||
|
) (*InclusionCommitment, error) {
|
||||||
|
if typeUrl == protobufs.IntrinsicExecutionOutputType {
|
||||||
|
digest := sha3.NewShake256()
|
||||||
|
_, err := digest.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
expand := make([]byte, 1024)
|
||||||
|
_, err = digest.Read(expand)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
poly, err := k.prover.BytesToPolynomial(expand)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "commit")
|
||||||
|
}
|
||||||
|
|
||||||
|
k.logger.Debug("proving execution output for inclusion")
|
||||||
|
polys, err := kzg.FFT(
|
||||||
|
poly,
|
||||||
|
*curves.BLS48581(
|
||||||
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
|
),
|
||||||
|
16,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prove")
|
||||||
|
}
|
||||||
|
|
||||||
|
k.logger.Debug("converted execution output chunk to evaluation form")
|
||||||
|
|
||||||
|
k.logger.Debug("creating kzg commitment")
|
||||||
|
points, err := k.prover.Commit(polys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prove")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &InclusionCommitment{
|
||||||
|
TypeUrl: typeUrl,
|
||||||
|
Data: data,
|
||||||
|
Commitment: points.ToAffineCompressed(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
poly, err := k.prover.BytesToPolynomial(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "commit")
|
||||||
|
}
|
||||||
|
|
||||||
|
points, err := k.prover.Commit(poly)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "commit")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &InclusionCommitment{
|
||||||
|
TypeUrl: typeUrl,
|
||||||
|
Data: data,
|
||||||
|
Commitment: points.ToAffineCompressed(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProveAggregate implements InclusionProver.
|
||||||
|
func (k *KZGInclusionProver) ProveAggregate(
|
||||||
|
commits []*InclusionCommitment,
|
||||||
|
) (*InclusionAggregateProof, error) {
|
||||||
|
polys := [][]curves.PairingScalar{}
|
||||||
|
commitPoints := []curves.PairingPoint{}
|
||||||
|
for _, commit := range commits {
|
||||||
|
switch commit.TypeUrl {
|
||||||
|
case protobufs.IntrinsicExecutionOutputType:
|
||||||
|
k.logger.Debug("confirming inclusion in aggregate")
|
||||||
|
digest := sha3.NewShake256()
|
||||||
|
_, err := digest.Write(commit.Data)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
expand := make([]byte, 1024)
|
||||||
|
_, err = digest.Read(expand)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
poly, err := k.prover.BytesToPolynomial(expand)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
evalPoly, err := kzg.FFT(
|
||||||
|
poly,
|
||||||
|
*curves.BLS48581(
|
||||||
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
|
),
|
||||||
|
16,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error performing fast fourier transform on key bundle",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
k.logger.Debug(
|
||||||
|
"created fft of polynomial",
|
||||||
|
zap.Int("poly_size", len(evalPoly)),
|
||||||
|
)
|
||||||
|
|
||||||
|
polys = append(polys, evalPoly)
|
||||||
|
|
||||||
|
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
||||||
|
commit.Commitment,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
commitPoints = append(commitPoints, c.(curves.PairingPoint))
|
||||||
|
default:
|
||||||
|
k.logger.Debug("confirming inclusion in aggregate")
|
||||||
|
poly, err := k.prover.BytesToPolynomial(commit.Data)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 128-len(poly); i++ {
|
||||||
|
poly = append(
|
||||||
|
poly,
|
||||||
|
curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
evalPoly, err := kzg.FFT(
|
||||||
|
poly,
|
||||||
|
*curves.BLS48581(
|
||||||
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
|
),
|
||||||
|
128,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error performing fast fourier transform on key bundle",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
k.logger.Debug(
|
||||||
|
"created fft of polynomial",
|
||||||
|
zap.Int("poly_size", len(evalPoly)),
|
||||||
|
)
|
||||||
|
|
||||||
|
polys = append(polys, evalPoly)
|
||||||
|
|
||||||
|
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
||||||
|
commit.Commitment,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
commitPoints = append(commitPoints, c.(curves.PairingPoint))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proof, commitment, err := k.prover.ProveAggregate(
|
||||||
|
polys,
|
||||||
|
commitPoints,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
if proof.IsIdentity() {
|
||||||
|
return nil, errors.Wrap(errors.New("invalid proof"), "prove aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &InclusionAggregateProof{
|
||||||
|
InclusionCommitments: commits,
|
||||||
|
AggregateCommitment: commitment.ToAffineCompressed(),
|
||||||
|
Proof: proof.ToAffineCompressed(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAggregate implements InclusionProver.
|
||||||
|
func (k *KZGInclusionProver) VerifyAggregate(
|
||||||
|
proof *InclusionAggregateProof,
|
||||||
|
) (bool, error) {
|
||||||
|
polys := [][]curves.PairingScalar{}
|
||||||
|
commitPoints := []curves.PairingPoint{}
|
||||||
|
for _, commit := range proof.InclusionCommitments {
|
||||||
|
poly, err := k.prover.BytesToPolynomial(commit.Data)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrap(err, "verify aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
polys = append(polys, poly)
|
||||||
|
|
||||||
|
point, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
||||||
|
commit.Commitment,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrap(err, "verify aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
commitPoints = append(commitPoints, point.(curves.PairingPoint))
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregate, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
||||||
|
proof.AggregateCommitment,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrap(err, "verify aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
proofPoint, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
||||||
|
proof.Proof,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrap(err, "verify aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
verify, err := k.prover.VerifyAggregateProof(
|
||||||
|
polys,
|
||||||
|
commitPoints,
|
||||||
|
aggregate.(curves.PairingPoint),
|
||||||
|
proofPoint.(curves.PairingPoint),
|
||||||
|
)
|
||||||
|
return verify, errors.Wrap(err, "verify aggregate")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KZGInclusionProver) VerifyFrame(
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
) error {
|
||||||
|
aggregateCommitments := []curves.PairingPoint{}
|
||||||
|
for i := 0; i < (len(frame.Input)-516)/74; i++ {
|
||||||
|
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
||||||
|
frame.Input[516+(i*74) : 516+(i*74)+74],
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
aggregateCommitments = append(aggregateCommitments, c.(curves.PairingPoint))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(aggregateCommitments) != len(frame.AggregateProofs) {
|
||||||
|
k.logger.Error(
|
||||||
|
"commit length mismatched proof for frame",
|
||||||
|
zap.Int("commit_length", len(aggregateCommitments)),
|
||||||
|
zap.Int("proof_length", len(frame.AggregateProofs)),
|
||||||
|
)
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("commit length mismatched proof for frame"),
|
||||||
|
"verify frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, proof := range frame.AggregateProofs {
|
||||||
|
aggregatePoly := [][]curves.PairingScalar{}
|
||||||
|
commitments := []curves.PairingPoint{}
|
||||||
|
|
||||||
|
for _, commit := range proof.GetInclusionCommitments() {
|
||||||
|
switch commit.TypeUrl {
|
||||||
|
case protobufs.IntrinsicExecutionOutputType:
|
||||||
|
k.logger.Debug("confirming inclusion in aggregate")
|
||||||
|
digest := sha3.NewShake256()
|
||||||
|
_, err := digest.Write(commit.Data)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
expand := make([]byte, 1024)
|
||||||
|
_, err = digest.Read(expand)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
poly, err := k.prover.BytesToPolynomial(expand)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
evalPoly, err := kzg.FFT(
|
||||||
|
poly,
|
||||||
|
*curves.BLS48581(
|
||||||
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
|
),
|
||||||
|
16,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error performing fast fourier transform on key bundle",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
k.logger.Debug(
|
||||||
|
"created fft of polynomial",
|
||||||
|
zap.Int("poly_size", len(evalPoly)),
|
||||||
|
)
|
||||||
|
|
||||||
|
aggregatePoly = append(aggregatePoly, evalPoly)
|
||||||
|
|
||||||
|
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
||||||
|
commit.Commitment,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
commitments = append(commitments, c.(curves.PairingPoint))
|
||||||
|
default:
|
||||||
|
k.logger.Debug("confirming inclusion in aggregate")
|
||||||
|
poly, err := k.prover.BytesToPolynomial(commit.Data)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error converting key bundle to polynomial",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 128-len(poly); i++ {
|
||||||
|
poly = append(
|
||||||
|
poly,
|
||||||
|
curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
evalPoly, err := kzg.FFT(
|
||||||
|
poly,
|
||||||
|
*curves.BLS48581(
|
||||||
|
curves.BLS48581G1().NewGeneratorPoint(),
|
||||||
|
),
|
||||||
|
128,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"error performing fast fourier transform on key bundle",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
k.logger.Debug(
|
||||||
|
"created fft of polynomial",
|
||||||
|
zap.Int("poly_size", len(evalPoly)),
|
||||||
|
)
|
||||||
|
|
||||||
|
aggregatePoly = append(aggregatePoly, evalPoly)
|
||||||
|
|
||||||
|
c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed(
|
||||||
|
commit.Commitment,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
commitments = append(commitments, c.(curves.PairingPoint))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
||||||
|
proof.Proof,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := k.prover.VerifyAggregateProof(
|
||||||
|
aggregatePoly,
|
||||||
|
commitments,
|
||||||
|
aggregateCommitments[i],
|
||||||
|
p.(curves.PairingPoint),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
k.logger.Error(
|
||||||
|
"could not verify clock frame",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.Wrap(err, "verify frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !result {
|
||||||
|
k.logger.Error("could not verify clock frame", zap.Error(err))
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid proof"),
|
||||||
|
"verify frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ InclusionProver = (*KZGInclusionProver)(nil)
|
72
node/crypto/kzg_inclusion_prover_test.go
Normal file
72
node/crypto/kzg_inclusion_prover_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package crypto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cloudflare/circl/sign/ed448"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/kzg"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestKZGVerifyFrame(t *testing.T) {
|
||||||
|
kzg.TestInit("../ceremony.json")
|
||||||
|
data := make([]byte, 1024)
|
||||||
|
rand.Read(data)
|
||||||
|
|
||||||
|
l, _ := zap.NewProduction()
|
||||||
|
inclusionProver := crypto.NewKZGInclusionProver(l)
|
||||||
|
|
||||||
|
commitment, err := inclusionProver.Commit(
|
||||||
|
data,
|
||||||
|
protobufs.IntrinsicExecutionOutputType,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
proof, err := inclusionProver.ProveAggregate(
|
||||||
|
[]*crypto.InclusionCommitment{commitment},
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
frame := &protobufs.ClockFrame{
|
||||||
|
Filter: []byte{0x00},
|
||||||
|
FrameNumber: 1,
|
||||||
|
Input: bytes.Repeat([]byte{0x00}, 516),
|
||||||
|
Output: bytes.Repeat([]byte{0x00}, 516),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, priv, _ := ed448.GenerateKey(rand.Reader)
|
||||||
|
w := crypto.NewWesolowskiFrameProver(l)
|
||||||
|
frame, err = w.ProveDataClockFrame(
|
||||||
|
frame,
|
||||||
|
[][]byte{proof.AggregateCommitment},
|
||||||
|
[]*protobufs.InclusionAggregateProof{
|
||||||
|
{
|
||||||
|
Filter: []byte{0x00},
|
||||||
|
FrameNumber: 1,
|
||||||
|
InclusionCommitments: []*protobufs.InclusionCommitment{
|
||||||
|
{
|
||||||
|
Filter: []byte{0x00},
|
||||||
|
FrameNumber: 1,
|
||||||
|
TypeUrl: proof.InclusionCommitments[0].TypeUrl,
|
||||||
|
Commitment: proof.InclusionCommitments[0].Commitment,
|
||||||
|
Data: data,
|
||||||
|
Position: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Proof: proof.Proof,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
priv,
|
||||||
|
time.Now().UnixMilli(),
|
||||||
|
100,
|
||||||
|
)
|
||||||
|
|
||||||
|
err = inclusionProver.VerifyFrame(frame)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package crypto
|
package shuffle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -7,10 +7,16 @@ import (
|
|||||||
"filippo.io/edwards25519"
|
"filippo.io/edwards25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
var lBE = []byte{16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 222, 249, 222, 162, 247, 156, 214, 88, 18, 99, 26, 92, 245, 211, 236}
|
var lBE = []byte{
|
||||||
|
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 222, 249, 222, 162, 247,
|
||||||
|
156, 214, 88, 18, 99, 26, 92, 245, 211, 236,
|
||||||
|
}
|
||||||
var lBigInt = big.NewInt(0).SetBytes(lBE)
|
var lBigInt = big.NewInt(0).SetBytes(lBE)
|
||||||
|
|
||||||
func genPolyFrags(secret *edwards25519.Scalar, total, threshold int) []*edwards25519.Scalar {
|
func genPolyFrags(
|
||||||
|
secret *edwards25519.Scalar,
|
||||||
|
total, threshold int,
|
||||||
|
) []*edwards25519.Scalar {
|
||||||
coeffs := []*edwards25519.Scalar{}
|
coeffs := []*edwards25519.Scalar{}
|
||||||
coeffs = append(coeffs, secret)
|
coeffs = append(coeffs, secret)
|
||||||
|
|
||||||
@ -48,7 +54,10 @@ func genPolyFrags(secret *edwards25519.Scalar, total, threshold int) []*edwards2
|
|||||||
return frags
|
return frags
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShamirSplitMatrix(matrix [][]*edwards25519.Scalar, total, threshold int) [][][]*edwards25519.Scalar {
|
func ShamirSplitMatrix(
|
||||||
|
matrix [][]*edwards25519.Scalar,
|
||||||
|
total, threshold int,
|
||||||
|
) [][][]*edwards25519.Scalar {
|
||||||
shamirMatrix := make([][][]*edwards25519.Scalar, len(matrix))
|
shamirMatrix := make([][][]*edwards25519.Scalar, len(matrix))
|
||||||
|
|
||||||
for x := 0; x < len(matrix); x++ {
|
for x := 0; x < len(matrix); x++ {
|
||||||
@ -79,7 +88,9 @@ func AddMatrices(matrices ...[][]*edwards25519.Scalar) [][]*edwards25519.Scalar
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRandomVectorShares(length, total, threshold int) [][]*edwards25519.Scalar {
|
func GenerateRandomVectorShares(
|
||||||
|
length, total, threshold int,
|
||||||
|
) [][]*edwards25519.Scalar {
|
||||||
result := make([][]*edwards25519.Scalar, length)
|
result := make([][]*edwards25519.Scalar, length)
|
||||||
|
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
@ -93,7 +104,10 @@ func GenerateRandomVectorShares(length, total, threshold int) [][]*edwards25519.
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func InterpolatePolynomialShares(shares []*edwards25519.Scalar, ids []int) *edwards25519.Scalar {
|
func InterpolatePolynomialShares(
|
||||||
|
shares []*edwards25519.Scalar,
|
||||||
|
ids []int,
|
||||||
|
) *edwards25519.Scalar {
|
||||||
var reconstructedSum *edwards25519.Scalar
|
var reconstructedSum *edwards25519.Scalar
|
||||||
|
|
||||||
for j := 0; j < len(ids); j++ {
|
for j := 0; j < len(ids); j++ {
|
||||||
@ -116,7 +130,10 @@ func InterpolatePolynomialShares(shares []*edwards25519.Scalar, ids []int) *edwa
|
|||||||
|
|
||||||
coeffDenom.Invert(coeffDenom)
|
coeffDenom.Invert(coeffDenom)
|
||||||
coeffNum.Multiply(coeffNum, coeffDenom)
|
coeffNum.Multiply(coeffNum, coeffDenom)
|
||||||
reconstructedFrag := edwards25519.NewScalar().Multiply(coeffNum, shares[ids[j]-1])
|
reconstructedFrag := edwards25519.NewScalar().Multiply(
|
||||||
|
coeffNum,
|
||||||
|
shares[ids[j]-1],
|
||||||
|
)
|
||||||
|
|
||||||
if reconstructedSum == nil {
|
if reconstructedSum == nil {
|
||||||
reconstructedSum = reconstructedFrag
|
reconstructedSum = reconstructedFrag
|
||||||
@ -128,7 +145,9 @@ func InterpolatePolynomialShares(shares []*edwards25519.Scalar, ids []int) *edwa
|
|||||||
return reconstructedSum
|
return reconstructedSum
|
||||||
}
|
}
|
||||||
|
|
||||||
func LUDecompose(matrix [][]*edwards25519.Scalar) ([][]*edwards25519.Scalar, [][]*edwards25519.Scalar) {
|
func LUDecompose(
|
||||||
|
matrix [][]*edwards25519.Scalar,
|
||||||
|
) ([][]*edwards25519.Scalar, [][]*edwards25519.Scalar) {
|
||||||
imax := 0
|
imax := 0
|
||||||
maxA := edwards25519.NewScalar()
|
maxA := edwards25519.NewScalar()
|
||||||
N := len(matrix)
|
N := len(matrix)
|
||||||
@ -141,18 +160,24 @@ func LUDecompose(matrix [][]*edwards25519.Scalar) ([][]*edwards25519.Scalar, [][
|
|||||||
pm[i] = make([]*edwards25519.Scalar, N)
|
pm[i] = make([]*edwards25519.Scalar, N)
|
||||||
p[i] = i
|
p[i] = i
|
||||||
for j := 0; j < N; j++ {
|
for j := 0; j < N; j++ {
|
||||||
newA[i][j], _ = edwards25519.NewScalar().SetCanonicalBytes(matrix[i][j].Bytes())
|
newA[i][j], _ = edwards25519.NewScalar().SetCanonicalBytes(
|
||||||
|
matrix[i][j].Bytes(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scalarOne, _ := edwards25519.NewScalar().SetCanonicalBytes(BigIntToLEBytes(big.NewInt(int64(1))))
|
scalarOne, _ := edwards25519.NewScalar().SetCanonicalBytes(
|
||||||
|
BigIntToLEBytes(big.NewInt(int64(1))),
|
||||||
|
)
|
||||||
|
|
||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
maxA = edwards25519.NewScalar()
|
maxA = edwards25519.NewScalar()
|
||||||
imax = i
|
imax = i
|
||||||
|
|
||||||
for k := i; k < N; k++ {
|
for k := i; k < N; k++ {
|
||||||
if LEBytesToBigInt(newA[k][i].Bytes()).Cmp(LEBytesToBigInt(maxA.Bytes())) > 0 {
|
if LEBytesToBigInt(newA[k][i].Bytes()).Cmp(
|
||||||
|
LEBytesToBigInt(maxA.Bytes()),
|
||||||
|
) > 0 {
|
||||||
maxA = newA[k][i]
|
maxA = newA[k][i]
|
||||||
imax = k
|
imax = k
|
||||||
}
|
}
|
||||||
@ -171,10 +196,16 @@ func LUDecompose(matrix [][]*edwards25519.Scalar) ([][]*edwards25519.Scalar, [][
|
|||||||
}
|
}
|
||||||
|
|
||||||
for j := i + 1; j < N; j++ {
|
for j := i + 1; j < N; j++ {
|
||||||
newA[j][i].Multiply(newA[j][i], edwards25519.NewScalar().Invert(newA[i][i]))
|
newA[j][i].Multiply(
|
||||||
|
newA[j][i],
|
||||||
|
edwards25519.NewScalar().Invert(newA[i][i]),
|
||||||
|
)
|
||||||
|
|
||||||
for k := i + 1; k < N; k++ {
|
for k := i + 1; k < N; k++ {
|
||||||
newA[j][k].Subtract(newA[j][k], edwards25519.NewScalar().Multiply(newA[j][i], newA[i][k]))
|
newA[j][k].Subtract(newA[j][k], edwards25519.NewScalar().Multiply(
|
||||||
|
newA[j][i],
|
||||||
|
newA[i][k],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,13 +236,19 @@ func Invert(matrix [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|||||||
ia[i][j] = edwards25519.NewScalar().Set(p[i][j])
|
ia[i][j] = edwards25519.NewScalar().Set(p[i][j])
|
||||||
|
|
||||||
for k := 0; k < i; k++ {
|
for k := 0; k < i; k++ {
|
||||||
ia[i][j].Subtract(ia[i][j], edwards25519.NewScalar().Multiply(a[i][k], ia[k][j]))
|
ia[i][j].Subtract(ia[i][j], edwards25519.NewScalar().Multiply(
|
||||||
|
a[i][k],
|
||||||
|
ia[k][j],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := len(matrix) - 1; i >= 0; i-- {
|
for i := len(matrix) - 1; i >= 0; i-- {
|
||||||
for k := i + 1; k < len(matrix); k++ {
|
for k := i + 1; k < len(matrix); k++ {
|
||||||
ia[i][j].Subtract(ia[i][j], edwards25519.NewScalar().Multiply(a[i][k], ia[k][j]))
|
ia[i][j].Subtract(ia[i][j], edwards25519.NewScalar().Multiply(
|
||||||
|
a[i][k],
|
||||||
|
ia[k][j],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
ia[i][j].Multiply(ia[i][j], edwards25519.NewScalar().Invert(a[i][i]))
|
ia[i][j].Multiply(ia[i][j], edwards25519.NewScalar().Invert(a[i][i]))
|
||||||
@ -221,7 +258,10 @@ func Invert(matrix [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|||||||
return ia
|
return ia
|
||||||
}
|
}
|
||||||
|
|
||||||
func InterpolateMatrixShares(matrixShares [][][]*edwards25519.Scalar, ids []int) [][]*edwards25519.Scalar {
|
func InterpolateMatrixShares(
|
||||||
|
matrixShares [][][]*edwards25519.Scalar,
|
||||||
|
ids []int,
|
||||||
|
) [][]*edwards25519.Scalar {
|
||||||
matrix := make([][]*edwards25519.Scalar, len(matrixShares))
|
matrix := make([][]*edwards25519.Scalar, len(matrixShares))
|
||||||
|
|
||||||
for x := 0; x < len(matrix); x++ {
|
for x := 0; x < len(matrix); x++ {
|
||||||
@ -241,10 +281,17 @@ func ScalarMult(a int, b [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|||||||
|
|
||||||
for y := 0; y < len(b[0]); y++ {
|
for y := 0; y < len(b[0]); y++ {
|
||||||
if a >= 0 {
|
if a >= 0 {
|
||||||
prod[x][y], _ = edwards25519.NewScalar().SetCanonicalBytes(BigIntToLEBytes(big.NewInt(int64(a))))
|
prod[x][y], _ = edwards25519.NewScalar().SetCanonicalBytes(
|
||||||
|
BigIntToLEBytes(big.NewInt(int64(a))),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
negA, _ := edwards25519.NewScalar().SetCanonicalBytes(BigIntToLEBytes(big.NewInt(int64(-a))))
|
negA, _ := edwards25519.NewScalar().SetCanonicalBytes(
|
||||||
prod[x][y] = edwards25519.NewScalar().Subtract(edwards25519.NewScalar(), negA)
|
BigIntToLEBytes(big.NewInt(int64(-a))),
|
||||||
|
)
|
||||||
|
prod[x][y] = edwards25519.NewScalar().Subtract(
|
||||||
|
edwards25519.NewScalar(),
|
||||||
|
negA,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
prod[x][y] = prod[x][y].Multiply(prod[x][y], b[x][y])
|
prod[x][y] = prod[x][y].Multiply(prod[x][y], b[x][y])
|
||||||
@ -254,7 +301,9 @@ func ScalarMult(a int, b [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|||||||
return prod
|
return prod
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateDotProduct(a, b [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
func GenerateDotProduct(
|
||||||
|
a, b [][]*edwards25519.Scalar,
|
||||||
|
) [][]*edwards25519.Scalar {
|
||||||
if len(a[0]) != len(b) {
|
if len(a[0]) != len(b) {
|
||||||
panic("cannot generate dot product of a and b - mismatched length")
|
panic("cannot generate dot product of a and b - mismatched length")
|
||||||
}
|
}
|
||||||
@ -276,7 +325,9 @@ func GenerateDotProduct(a, b [][]*edwards25519.Scalar) [][]*edwards25519.Scalar
|
|||||||
return abMatrix
|
return abMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRandomMatrixAndInverseShares(size, total, threshold int) [2][][][]*edwards25519.Scalar {
|
func GenerateRandomMatrixAndInverseShares(
|
||||||
|
size, total, threshold int,
|
||||||
|
) [2][][][]*edwards25519.Scalar {
|
||||||
output := make([][]*edwards25519.Scalar, size)
|
output := make([][]*edwards25519.Scalar, size)
|
||||||
for x := 0; x < size; x++ {
|
for x := 0; x < size; x++ {
|
||||||
output[x] = make([]*edwards25519.Scalar, size)
|
output[x] = make([]*edwards25519.Scalar, size)
|
||||||
@ -294,7 +345,9 @@ func GenerateRandomMatrixAndInverseShares(size, total, threshold int) [2][][][]*
|
|||||||
return [2][][][]*edwards25519.Scalar{splitOutput, splitInverse}
|
return [2][][][]*edwards25519.Scalar{splitOutput, splitInverse}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRandomBeaverTripleMatrixShares(size, total, threshold int) [3][][][]*edwards25519.Scalar {
|
func GenerateRandomBeaverTripleMatrixShares(
|
||||||
|
size, total, threshold int,
|
||||||
|
) [3][][][]*edwards25519.Scalar {
|
||||||
uMatrix := make([][]*edwards25519.Scalar, size)
|
uMatrix := make([][]*edwards25519.Scalar, size)
|
||||||
vMatrix := make([][]*edwards25519.Scalar, size)
|
vMatrix := make([][]*edwards25519.Scalar, size)
|
||||||
|
|
||||||
@ -321,7 +374,9 @@ func GenerateRandomBeaverTripleMatrixShares(size, total, threshold int) [3][][][
|
|||||||
vMatrixShares := ShamirSplitMatrix(vMatrix, total, threshold)
|
vMatrixShares := ShamirSplitMatrix(vMatrix, total, threshold)
|
||||||
uvMatrixShares := ShamirSplitMatrix(uvMatrix, total, threshold)
|
uvMatrixShares := ShamirSplitMatrix(uvMatrix, total, threshold)
|
||||||
|
|
||||||
return [3][][][]*edwards25519.Scalar{uMatrixShares, vMatrixShares, uvMatrixShares}
|
return [3][][][]*edwards25519.Scalar{
|
||||||
|
uMatrixShares, vMatrixShares, uvMatrixShares,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GeneratePermutationMatrix(size int) [][]*edwards25519.Scalar {
|
func GeneratePermutationMatrix(size int) [][]*edwards25519.Scalar {
|
@ -1,4 +1,4 @@
|
|||||||
package crypto_test
|
package shuffle_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -7,11 +7,11 @@ import (
|
|||||||
|
|
||||||
"filippo.io/edwards25519"
|
"filippo.io/edwards25519"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/shuffle"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGeneratePermutationMatrix(t *testing.T) {
|
func TestGeneratePermutationMatrix(t *testing.T) {
|
||||||
m := crypto.GeneratePermutationMatrix(6)
|
m := shuffle.GeneratePermutationMatrix(6)
|
||||||
for _, x := range m {
|
for _, x := range m {
|
||||||
ySum := byte(0x00)
|
ySum := byte(0x00)
|
||||||
for _, y := range x {
|
for _, y := range x {
|
||||||
@ -39,14 +39,14 @@ func verifyLagrange(t *testing.T, shares []*edwards25519.Scalar, expected *edwar
|
|||||||
var reconstructedSum *edwards25519.Scalar
|
var reconstructedSum *edwards25519.Scalar
|
||||||
|
|
||||||
for j := 0; j < threshold; j++ {
|
for j := 0; j < threshold; j++ {
|
||||||
oneLENumBytes := crypto.BigIntToLEBytes(big.NewInt(1))
|
oneLENumBytes := shuffle.BigIntToLEBytes(big.NewInt(1))
|
||||||
coeffNum, _ := edwards25519.NewScalar().SetCanonicalBytes(oneLENumBytes)
|
coeffNum, _ := edwards25519.NewScalar().SetCanonicalBytes(oneLENumBytes)
|
||||||
coeffDenom, _ := edwards25519.NewScalar().SetCanonicalBytes(oneLENumBytes)
|
coeffDenom, _ := edwards25519.NewScalar().SetCanonicalBytes(oneLENumBytes)
|
||||||
|
|
||||||
for k := 0; k < threshold; k++ {
|
for k := 0; k < threshold; k++ {
|
||||||
if j != k {
|
if j != k {
|
||||||
ikBytes := crypto.BigIntToLEBytes(big.NewInt(int64(i + k)))
|
ikBytes := shuffle.BigIntToLEBytes(big.NewInt(int64(i + k)))
|
||||||
ijBytes := crypto.BigIntToLEBytes(big.NewInt(int64(i + j)))
|
ijBytes := shuffle.BigIntToLEBytes(big.NewInt(int64(i + j)))
|
||||||
ikScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ikBytes)
|
ikScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ikBytes)
|
||||||
ijScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ijBytes)
|
ijScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ijBytes)
|
||||||
|
|
||||||
@ -78,8 +78,8 @@ func verifyLagrange(t *testing.T, shares []*edwards25519.Scalar, expected *edwar
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateShamirMatrix(t *testing.T) {
|
func TestGenerateShamirMatrix(t *testing.T) {
|
||||||
m := crypto.GeneratePermutationMatrix(6)
|
m := shuffle.GeneratePermutationMatrix(6)
|
||||||
sm := crypto.ShamirSplitMatrix(m, 10, 3)
|
sm := shuffle.ShamirSplitMatrix(m, 10, 3)
|
||||||
for xi, x := range sm {
|
for xi, x := range sm {
|
||||||
for yi, y := range x {
|
for yi, y := range x {
|
||||||
verifyLagrange(t, y, m[xi][yi], 10, 3)
|
verifyLagrange(t, y, m[xi][yi], 10, 3)
|
||||||
@ -88,11 +88,11 @@ func TestGenerateShamirMatrix(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMatrixDotProduct(t *testing.T) {
|
func TestMatrixDotProduct(t *testing.T) {
|
||||||
zeroBytes := crypto.BigIntToLEBytes(big.NewInt(0))
|
zeroBytes := shuffle.BigIntToLEBytes(big.NewInt(0))
|
||||||
oneBytes := crypto.BigIntToLEBytes(big.NewInt(1))
|
oneBytes := shuffle.BigIntToLEBytes(big.NewInt(1))
|
||||||
twoBytes := crypto.BigIntToLEBytes(big.NewInt(2))
|
twoBytes := shuffle.BigIntToLEBytes(big.NewInt(2))
|
||||||
threeBytes := crypto.BigIntToLEBytes(big.NewInt(3))
|
threeBytes := shuffle.BigIntToLEBytes(big.NewInt(3))
|
||||||
fourBytes := crypto.BigIntToLEBytes(big.NewInt(4))
|
fourBytes := shuffle.BigIntToLEBytes(big.NewInt(4))
|
||||||
|
|
||||||
zero, _ := edwards25519.NewScalar().SetCanonicalBytes(zeroBytes)
|
zero, _ := edwards25519.NewScalar().SetCanonicalBytes(zeroBytes)
|
||||||
one, _ := edwards25519.NewScalar().SetCanonicalBytes(oneBytes)
|
one, _ := edwards25519.NewScalar().SetCanonicalBytes(oneBytes)
|
||||||
@ -110,7 +110,7 @@ func TestMatrixDotProduct(t *testing.T) {
|
|||||||
{three, two, four},
|
{three, two, four},
|
||||||
}
|
}
|
||||||
|
|
||||||
abMatrix := crypto.GenerateDotProduct(aMatrix, bMatrix)
|
abMatrix := shuffle.GenerateDotProduct(aMatrix, bMatrix)
|
||||||
assert.Equal(t, byte(0x0a), abMatrix[0][0].Bytes()[0])
|
assert.Equal(t, byte(0x0a), abMatrix[0][0].Bytes()[0])
|
||||||
assert.Equal(t, byte(0x06), abMatrix[0][1].Bytes()[0])
|
assert.Equal(t, byte(0x06), abMatrix[0][1].Bytes()[0])
|
||||||
assert.Equal(t, byte(0x0c), abMatrix[0][2].Bytes()[0])
|
assert.Equal(t, byte(0x0c), abMatrix[0][2].Bytes()[0])
|
||||||
@ -123,15 +123,15 @@ func TestMatrixDotProduct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateRandomBeaverTripleMatrixShares(t *testing.T) {
|
func TestGenerateRandomBeaverTripleMatrixShares(t *testing.T) {
|
||||||
beaverTripleShares := crypto.GenerateRandomBeaverTripleMatrixShares(6, 10, 3)
|
beaverTripleShares := shuffle.GenerateRandomBeaverTripleMatrixShares(6, 10, 3)
|
||||||
|
|
||||||
uMatrixShares := beaverTripleShares[0]
|
uMatrixShares := beaverTripleShares[0]
|
||||||
vMatrixShares := beaverTripleShares[1]
|
vMatrixShares := beaverTripleShares[1]
|
||||||
uvMatrixShares := beaverTripleShares[2]
|
uvMatrixShares := beaverTripleShares[2]
|
||||||
|
|
||||||
uMatrix := crypto.InterpolateMatrixShares(uMatrixShares, []int{1, 2, 3})
|
uMatrix := shuffle.InterpolateMatrixShares(uMatrixShares, []int{1, 2, 3})
|
||||||
vMatrix := crypto.InterpolateMatrixShares(vMatrixShares, []int{1, 2, 3})
|
vMatrix := shuffle.InterpolateMatrixShares(vMatrixShares, []int{1, 2, 3})
|
||||||
uvMatrix := crypto.InterpolateMatrixShares(uvMatrixShares, []int{1, 2, 3})
|
uvMatrix := shuffle.InterpolateMatrixShares(uvMatrixShares, []int{1, 2, 3})
|
||||||
|
|
||||||
for x := 0; x < len(uMatrixShares); x++ {
|
for x := 0; x < len(uMatrixShares); x++ {
|
||||||
for y := 0; y < len(uMatrixShares[0]); y++ {
|
for y := 0; y < len(uMatrixShares[0]); y++ {
|
||||||
@ -141,21 +141,21 @@ func TestGenerateRandomBeaverTripleMatrixShares(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uvCheck := crypto.GenerateDotProduct(uMatrix, vMatrix)
|
uvCheck := shuffle.GenerateDotProduct(uMatrix, vMatrix)
|
||||||
assert.Equal(t, uvMatrix, uvCheck)
|
assert.Equal(t, uvMatrix, uvCheck)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPermutationMatrix(t *testing.T) {
|
func TestPermutationMatrix(t *testing.T) {
|
||||||
permutationMatrix1 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix1 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrix2 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix2 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrix3 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix3 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrix4 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix4 := shuffle.GeneratePermutationMatrix(6)
|
||||||
|
|
||||||
permutationMatrix := crypto.GenerateDotProduct(permutationMatrix1, permutationMatrix2)
|
permutationMatrix := shuffle.GenerateDotProduct(permutationMatrix1, permutationMatrix2)
|
||||||
permutationMatrix = crypto.GenerateDotProduct(permutationMatrix, permutationMatrix3)
|
permutationMatrix = shuffle.GenerateDotProduct(permutationMatrix, permutationMatrix3)
|
||||||
permutationMatrix = crypto.GenerateDotProduct(permutationMatrix, permutationMatrix4)
|
permutationMatrix = shuffle.GenerateDotProduct(permutationMatrix, permutationMatrix4)
|
||||||
|
|
||||||
one, _ := edwards25519.NewScalar().SetCanonicalBytes(crypto.BigIntToLEBytes(big.NewInt(1)))
|
one, _ := edwards25519.NewScalar().SetCanonicalBytes(shuffle.BigIntToLEBytes(big.NewInt(1)))
|
||||||
for x := 0; x < 6; x++ {
|
for x := 0; x < 6; x++ {
|
||||||
sumX := edwards25519.NewScalar()
|
sumX := edwards25519.NewScalar()
|
||||||
|
|
||||||
@ -178,14 +178,14 @@ func TestPermutationMatrix(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPermutationSharing(t *testing.T) {
|
func TestPermutationSharing(t *testing.T) {
|
||||||
permutationMatrix1 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix1 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrix2 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix2 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrix3 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix3 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrix4 := crypto.GeneratePermutationMatrix(6)
|
permutationMatrix4 := shuffle.GeneratePermutationMatrix(6)
|
||||||
permutationMatrixShares1 := crypto.ShamirSplitMatrix(permutationMatrix1, 4, 3)
|
permutationMatrixShares1 := shuffle.ShamirSplitMatrix(permutationMatrix1, 4, 3)
|
||||||
permutationMatrixShares2 := crypto.ShamirSplitMatrix(permutationMatrix2, 4, 3)
|
permutationMatrixShares2 := shuffle.ShamirSplitMatrix(permutationMatrix2, 4, 3)
|
||||||
permutationMatrixShares3 := crypto.ShamirSplitMatrix(permutationMatrix3, 4, 3)
|
permutationMatrixShares3 := shuffle.ShamirSplitMatrix(permutationMatrix3, 4, 3)
|
||||||
permutationMatrixShares4 := crypto.ShamirSplitMatrix(permutationMatrix4, 4, 3)
|
permutationMatrixShares4 := shuffle.ShamirSplitMatrix(permutationMatrix4, 4, 3)
|
||||||
|
|
||||||
inverseShareMatrix1 := make([][][]*edwards25519.Scalar, 4)
|
inverseShareMatrix1 := make([][][]*edwards25519.Scalar, 4)
|
||||||
inverseShareMatrix2 := make([][][]*edwards25519.Scalar, 4)
|
inverseShareMatrix2 := make([][][]*edwards25519.Scalar, 4)
|
||||||
@ -213,9 +213,9 @@ func TestPermutationSharing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
beaverTripleShares1 := crypto.GenerateRandomBeaverTripleMatrixShares(6, 4, 3)
|
beaverTripleShares1 := shuffle.GenerateRandomBeaverTripleMatrixShares(6, 4, 3)
|
||||||
beaverTripleShares2 := crypto.GenerateRandomBeaverTripleMatrixShares(6, 4, 3)
|
beaverTripleShares2 := shuffle.GenerateRandomBeaverTripleMatrixShares(6, 4, 3)
|
||||||
beaverTripleShares3 := crypto.GenerateRandomBeaverTripleMatrixShares(6, 4, 3)
|
beaverTripleShares3 := shuffle.GenerateRandomBeaverTripleMatrixShares(6, 4, 3)
|
||||||
|
|
||||||
beaverTriplesAShares1 := beaverTripleShares1[0]
|
beaverTriplesAShares1 := beaverTripleShares1[0]
|
||||||
beaverTriplesBShares1 := beaverTripleShares1[1]
|
beaverTriplesBShares1 := beaverTripleShares1[1]
|
||||||
@ -310,18 +310,18 @@ func TestPermutationSharing(t *testing.T) {
|
|||||||
// f = b - v
|
// f = b - v
|
||||||
// (a - u)(b - v) = -ab + ub + av - uv + (ab-av) + (ab - ub) + uv
|
// (a - u)(b - v) = -ab + ub + av - uv + (ab-av) + (ab - ub) + uv
|
||||||
|
|
||||||
e1 := crypto.InterpolateMatrixShares(es1, []int{1, 2, 3, 4})
|
e1 := shuffle.InterpolateMatrixShares(es1, []int{1, 2, 3, 4})
|
||||||
f1 := crypto.InterpolateMatrixShares(fs1, []int{1, 2, 3, 4})
|
f1 := shuffle.InterpolateMatrixShares(fs1, []int{1, 2, 3, 4})
|
||||||
e2 := crypto.InterpolateMatrixShares(es2, []int{1, 2, 3, 4})
|
e2 := shuffle.InterpolateMatrixShares(es2, []int{1, 2, 3, 4})
|
||||||
f2 := crypto.InterpolateMatrixShares(fs2, []int{1, 2, 3, 4})
|
f2 := shuffle.InterpolateMatrixShares(fs2, []int{1, 2, 3, 4})
|
||||||
e3 := crypto.InterpolateMatrixShares(es3, []int{1, 2, 3, 4})
|
e3 := shuffle.InterpolateMatrixShares(es3, []int{1, 2, 3, 4})
|
||||||
f3 := crypto.InterpolateMatrixShares(fs3, []int{1, 2, 3, 4})
|
f3 := shuffle.InterpolateMatrixShares(fs3, []int{1, 2, 3, 4})
|
||||||
|
|
||||||
// mul(a, b) => <e> = <a> - <u>, <f> = <b> - <v>, <c> = -i * e * f + f * <a> + e * <b> + <z>
|
// mul(a, b) => <e> = <a> - <u>, <f> = <b> - <v>, <c> = -i * e * f + f * <a> + e * <b> + <z>
|
||||||
|
|
||||||
ef1 := crypto.GenerateDotProduct(e1, f1)
|
ef1 := shuffle.GenerateDotProduct(e1, f1)
|
||||||
ef2 := crypto.GenerateDotProduct(e2, f2)
|
ef2 := shuffle.GenerateDotProduct(e2, f2)
|
||||||
ef3 := crypto.GenerateDotProduct(e3, f3)
|
ef3 := shuffle.GenerateDotProduct(e3, f3)
|
||||||
fa1 := make([][][]*edwards25519.Scalar, 4)
|
fa1 := make([][][]*edwards25519.Scalar, 4)
|
||||||
fa2 := make([][][]*edwards25519.Scalar, 4)
|
fa2 := make([][][]*edwards25519.Scalar, 4)
|
||||||
fa3 := make([][][]*edwards25519.Scalar, 4)
|
fa3 := make([][][]*edwards25519.Scalar, 4)
|
||||||
@ -336,15 +336,15 @@ func TestPermutationSharing(t *testing.T) {
|
|||||||
inverseCS3 := make([][][]*edwards25519.Scalar, 6)
|
inverseCS3 := make([][][]*edwards25519.Scalar, 6)
|
||||||
|
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
fa1[i] = crypto.GenerateDotProduct(inverseShareMatrix1[i], f1)
|
fa1[i] = shuffle.GenerateDotProduct(inverseShareMatrix1[i], f1)
|
||||||
eb1[i] = crypto.GenerateDotProduct(e1, inverseShareMatrix2[i])
|
eb1[i] = shuffle.GenerateDotProduct(e1, inverseShareMatrix2[i])
|
||||||
fa2[i] = crypto.GenerateDotProduct(inverseShareMatrix2[i], f2)
|
fa2[i] = shuffle.GenerateDotProduct(inverseShareMatrix2[i], f2)
|
||||||
eb2[i] = crypto.GenerateDotProduct(e2, inverseShareMatrix3[i])
|
eb2[i] = shuffle.GenerateDotProduct(e2, inverseShareMatrix3[i])
|
||||||
fa3[i] = crypto.GenerateDotProduct(inverseShareMatrix3[i], f3)
|
fa3[i] = shuffle.GenerateDotProduct(inverseShareMatrix3[i], f3)
|
||||||
eb3[i] = crypto.GenerateDotProduct(e3, inverseShareMatrix4[i])
|
eb3[i] = shuffle.GenerateDotProduct(e3, inverseShareMatrix4[i])
|
||||||
cs1[i] = crypto.AddMatrices(crypto.ScalarMult(-1, ef1), fa1[i], eb1[i], inverseBeaverTriplesABShares1[i])
|
cs1[i] = shuffle.AddMatrices(shuffle.ScalarMult(-1, ef1), fa1[i], eb1[i], inverseBeaverTriplesABShares1[i])
|
||||||
cs2[i] = crypto.AddMatrices(crypto.ScalarMult(-1, ef2), fa2[i], eb2[i], inverseBeaverTriplesABShares2[i])
|
cs2[i] = shuffle.AddMatrices(shuffle.ScalarMult(-1, ef2), fa2[i], eb2[i], inverseBeaverTriplesABShares2[i])
|
||||||
cs3[i] = crypto.AddMatrices(crypto.ScalarMult(-1, ef3), fa3[i], eb3[i], inverseBeaverTriplesABShares3[i])
|
cs3[i] = shuffle.AddMatrices(shuffle.ScalarMult(-1, ef3), fa3[i], eb3[i], inverseBeaverTriplesABShares3[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
for x := 0; x < 6; x++ {
|
for x := 0; x < 6; x++ {
|
||||||
@ -360,12 +360,12 @@ func TestPermutationSharing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c1 := crypto.InterpolateMatrixShares(inverseCS1, []int{1, 2, 3, 4})
|
c1 := shuffle.InterpolateMatrixShares(inverseCS1, []int{1, 2, 3, 4})
|
||||||
c3 := crypto.InterpolateMatrixShares(inverseCS3, []int{1, 2, 3, 4})
|
c3 := shuffle.InterpolateMatrixShares(inverseCS3, []int{1, 2, 3, 4})
|
||||||
c := crypto.GenerateDotProduct(c1, c3)
|
c := shuffle.GenerateDotProduct(c1, c3)
|
||||||
ab := crypto.GenerateDotProduct(permutationMatrix1, permutationMatrix2)
|
ab := shuffle.GenerateDotProduct(permutationMatrix1, permutationMatrix2)
|
||||||
abc := crypto.GenerateDotProduct(ab, permutationMatrix3)
|
abc := shuffle.GenerateDotProduct(ab, permutationMatrix3)
|
||||||
abcd := crypto.GenerateDotProduct(abc, permutationMatrix4)
|
abcd := shuffle.GenerateDotProduct(abc, permutationMatrix4)
|
||||||
|
|
||||||
for x := 0; x < 6; x++ {
|
for x := 0; x < 6; x++ {
|
||||||
for y := 0; y < 6; y++ {
|
for y := 0; y < 6; y++ {
|
469
node/crypto/wesolowski_frame_prover.go
Normal file
469
node/crypto/wesolowski_frame_prover.go
Normal file
@ -0,0 +1,469 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/cloudflare/circl/sign/ed448"
|
||||||
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WesolowskiFrameProver struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWesolowskiFrameProver(logger *zap.Logger) *WesolowskiFrameProver {
|
||||||
|
return &WesolowskiFrameProver{
|
||||||
|
logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WesolowskiFrameProver) ProveMasterClockFrame(
|
||||||
|
previousFrame *protobufs.ClockFrame,
|
||||||
|
timestamp int64,
|
||||||
|
difficulty uint32,
|
||||||
|
) (*protobufs.ClockFrame, error) {
|
||||||
|
input := []byte{}
|
||||||
|
input = append(input, previousFrame.Filter...)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, previousFrame.FrameNumber+1)
|
||||||
|
input = binary.BigEndian.AppendUint32(input, difficulty)
|
||||||
|
input = append(input, previousFrame.Output[:]...)
|
||||||
|
|
||||||
|
b := sha3.Sum256(input)
|
||||||
|
v := vdf.New(difficulty, b)
|
||||||
|
v.Execute()
|
||||||
|
o := v.GetOutput()
|
||||||
|
|
||||||
|
previousSelectorBytes := [516]byte{}
|
||||||
|
copy(previousSelectorBytes[:], previousFrame.Output[:516])
|
||||||
|
|
||||||
|
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prove clock frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
frame := &protobufs.ClockFrame{
|
||||||
|
Filter: previousFrame.Filter,
|
||||||
|
FrameNumber: previousFrame.FrameNumber + 1,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
ParentSelector: parent.FillBytes(make([]byte, 32)),
|
||||||
|
Input: previousFrame.Output,
|
||||||
|
AggregateProofs: []*protobufs.InclusionAggregateProof{},
|
||||||
|
Output: o[:],
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WesolowskiFrameProver) VerifyMasterClockFrame(
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
) error {
|
||||||
|
input := []byte{}
|
||||||
|
input = append(input, frame.Filter...)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, frame.FrameNumber)
|
||||||
|
input = binary.BigEndian.AppendUint32(input, frame.Difficulty)
|
||||||
|
input = append(input, frame.Input...)
|
||||||
|
|
||||||
|
if len(frame.Input) < 516 {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(frame.AggregateProofs) > 0 {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame.PublicKeySignature != nil {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(frame.Input) != 516 {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := sha3.Sum256(input)
|
||||||
|
v := vdf.New(frame.Difficulty, b)
|
||||||
|
proof := [516]byte{}
|
||||||
|
copy(proof[:], frame.Output)
|
||||||
|
|
||||||
|
if !v.Verify(proof) {
|
||||||
|
w.logger.Error("invalid proof",
|
||||||
|
zap.Binary("filter", frame.Filter),
|
||||||
|
zap.Uint64("frame_number", frame.FrameNumber),
|
||||||
|
zap.Uint32("difficulty", frame.Difficulty),
|
||||||
|
zap.Binary("frame_input", frame.Input),
|
||||||
|
zap.Binary("frame_output", frame.Output),
|
||||||
|
)
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid proof"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
previousSelectorBytes := [516]byte{}
|
||||||
|
copy(previousSelectorBytes[:], frame.Input[:516])
|
||||||
|
|
||||||
|
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "verify clock frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
selector := new(big.Int).SetBytes(frame.ParentSelector)
|
||||||
|
if parent.Cmp(selector) != 0 {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("selector did not match input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WesolowskiFrameProver) CreateMasterGenesisFrame(
|
||||||
|
filter []byte,
|
||||||
|
seed []byte,
|
||||||
|
difficulty uint32,
|
||||||
|
) (
|
||||||
|
*protobufs.ClockFrame,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
b := sha3.Sum256(seed)
|
||||||
|
v := vdf.New(difficulty, b)
|
||||||
|
|
||||||
|
v.Execute()
|
||||||
|
o := v.GetOutput()
|
||||||
|
inputMessage := o[:]
|
||||||
|
|
||||||
|
w.logger.Debug("proving genesis frame")
|
||||||
|
input := []byte{}
|
||||||
|
input = append(input, filter...)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, 0)
|
||||||
|
input = binary.BigEndian.AppendUint32(input, difficulty)
|
||||||
|
if bytes.Equal(seed, []byte{0x00}) {
|
||||||
|
value := [516]byte{}
|
||||||
|
input = append(input, value[:]...)
|
||||||
|
} else {
|
||||||
|
input = append(input, seed...)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = sha3.Sum256(input)
|
||||||
|
v = vdf.New(difficulty, b)
|
||||||
|
|
||||||
|
v.Execute()
|
||||||
|
o = v.GetOutput()
|
||||||
|
|
||||||
|
frame := &protobufs.ClockFrame{
|
||||||
|
Filter: filter,
|
||||||
|
FrameNumber: 0,
|
||||||
|
Timestamp: 0,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
Input: inputMessage,
|
||||||
|
Output: o[:],
|
||||||
|
ParentSelector: []byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
AggregateProofs: []*protobufs.InclusionAggregateProof{},
|
||||||
|
PublicKeySignature: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WesolowskiFrameProver) ProveDataClockFrame(
|
||||||
|
previousFrame *protobufs.ClockFrame,
|
||||||
|
commitments [][]byte,
|
||||||
|
aggregateProofs []*protobufs.InclusionAggregateProof,
|
||||||
|
provingKey crypto.Signer,
|
||||||
|
timestamp int64,
|
||||||
|
difficulty uint32,
|
||||||
|
) (*protobufs.ClockFrame, error) {
|
||||||
|
var pubkey []byte
|
||||||
|
pubkeyType := keys.KeyTypeEd448
|
||||||
|
ed448PublicKey, ok := provingKey.Public().(ed448.PublicKey)
|
||||||
|
if ok {
|
||||||
|
pubkey = []byte(ed448PublicKey)
|
||||||
|
} else {
|
||||||
|
return nil, errors.Wrap(
|
||||||
|
errors.New("no valid signature provided"),
|
||||||
|
"prove clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := poseidon.HashBytes(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(
|
||||||
|
errors.New("could not hash proving key"),
|
||||||
|
"prove clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
address := h.Bytes()
|
||||||
|
input := []byte{}
|
||||||
|
input = append(input, previousFrame.Filter...)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, previousFrame.FrameNumber+1)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, uint64(timestamp))
|
||||||
|
input = binary.BigEndian.AppendUint32(input, difficulty)
|
||||||
|
input = append(input, address...)
|
||||||
|
input = append(input, previousFrame.Output[:]...)
|
||||||
|
|
||||||
|
commitmentInput := []byte{}
|
||||||
|
for _, commitment := range commitments {
|
||||||
|
commitmentInput = append(commitmentInput, commitment...)
|
||||||
|
}
|
||||||
|
|
||||||
|
input = append(input, commitmentInput...)
|
||||||
|
|
||||||
|
b := sha3.Sum256(input)
|
||||||
|
v := vdf.New(difficulty, b)
|
||||||
|
|
||||||
|
v.Execute()
|
||||||
|
o := v.GetOutput()
|
||||||
|
|
||||||
|
// TODO: make this configurable for signing algorithms that allow
|
||||||
|
// user-supplied hash functions
|
||||||
|
signature, err := provingKey.Sign(
|
||||||
|
rand.Reader,
|
||||||
|
append(append([]byte{}, b[:]...), o[:]...),
|
||||||
|
crypto.Hash(0),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(
|
||||||
|
err,
|
||||||
|
"prove",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
previousSelectorBytes := [516]byte{}
|
||||||
|
copy(previousSelectorBytes[:], previousFrame.Output[:516])
|
||||||
|
|
||||||
|
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prove clock frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
frame := &protobufs.ClockFrame{
|
||||||
|
Filter: previousFrame.Filter,
|
||||||
|
FrameNumber: previousFrame.FrameNumber + 1,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
ParentSelector: parent.Bytes(),
|
||||||
|
Input: append(
|
||||||
|
append([]byte{}, previousFrame.Output...),
|
||||||
|
commitmentInput...,
|
||||||
|
),
|
||||||
|
AggregateProofs: aggregateProofs,
|
||||||
|
Output: o[:],
|
||||||
|
}
|
||||||
|
|
||||||
|
switch pubkeyType {
|
||||||
|
case keys.KeyTypeEd448:
|
||||||
|
frame.PublicKeySignature = &protobufs.ClockFrame_PublicKeySignatureEd448{
|
||||||
|
PublicKeySignatureEd448: &protobufs.Ed448Signature{
|
||||||
|
Signature: signature,
|
||||||
|
PublicKey: &protobufs.Ed448PublicKey{
|
||||||
|
KeyValue: pubkey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, errors.Wrap(
|
||||||
|
errors.New("unsupported proving key"),
|
||||||
|
"prove clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WesolowskiFrameProver) CreateDataGenesisFrame(
|
||||||
|
filter []byte,
|
||||||
|
origin []byte,
|
||||||
|
difficulty uint32,
|
||||||
|
inclusionProof *InclusionAggregateProof,
|
||||||
|
proverKeys [][]byte,
|
||||||
|
preDusk bool,
|
||||||
|
) (*protobufs.ClockFrame, *tries.RollingFrecencyCritbitTrie, error) {
|
||||||
|
frameProverTrie := &tries.RollingFrecencyCritbitTrie{}
|
||||||
|
for _, s := range proverKeys {
|
||||||
|
addr, err := poseidon.HashBytes(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrBytes := addr.Bytes()
|
||||||
|
addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...)
|
||||||
|
frameProverTrie.Add(addrBytes, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.logger.Info("proving genesis frame")
|
||||||
|
input := []byte{}
|
||||||
|
input = append(input, filter...)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, 0)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, 0)
|
||||||
|
input = binary.BigEndian.AppendUint32(input, difficulty)
|
||||||
|
input = append(input, origin...)
|
||||||
|
if !preDusk {
|
||||||
|
input = append(input, inclusionProof.AggregateCommitment...)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := sha3.Sum256(input)
|
||||||
|
v := vdf.New(difficulty, b)
|
||||||
|
|
||||||
|
v.Execute()
|
||||||
|
o := v.GetOutput()
|
||||||
|
|
||||||
|
commitments := []*protobufs.InclusionCommitment{}
|
||||||
|
for i, commit := range inclusionProof.InclusionCommitments {
|
||||||
|
commitments = append(commitments, &protobufs.InclusionCommitment{
|
||||||
|
Filter: filter,
|
||||||
|
FrameNumber: 0,
|
||||||
|
Position: uint32(i),
|
||||||
|
TypeUrl: commit.TypeUrl,
|
||||||
|
Data: commit.Data,
|
||||||
|
Commitment: commit.Commitment,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
frame := &protobufs.ClockFrame{
|
||||||
|
Filter: filter,
|
||||||
|
FrameNumber: 0,
|
||||||
|
Timestamp: 0,
|
||||||
|
Difficulty: difficulty,
|
||||||
|
Input: append(
|
||||||
|
append([]byte{}, origin...),
|
||||||
|
inclusionProof.AggregateCommitment...,
|
||||||
|
),
|
||||||
|
Output: o[:],
|
||||||
|
ParentSelector: []byte{
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
AggregateProofs: []*protobufs.InclusionAggregateProof{
|
||||||
|
{
|
||||||
|
Filter: filter,
|
||||||
|
FrameNumber: 0,
|
||||||
|
InclusionCommitments: commitments,
|
||||||
|
Proof: inclusionProof.Proof,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PublicKeySignature: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, frameProverTrie, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WesolowskiFrameProver) VerifyDataClockFrame(
|
||||||
|
frame *protobufs.ClockFrame,
|
||||||
|
) error {
|
||||||
|
var pubkey []byte
|
||||||
|
var signature []byte
|
||||||
|
pubkeyType := keys.KeyTypeEd448
|
||||||
|
ed448PublicKey := frame.GetPublicKeySignatureEd448()
|
||||||
|
if ed448PublicKey != nil {
|
||||||
|
pubkey = ed448PublicKey.PublicKey.KeyValue
|
||||||
|
signature = ed448PublicKey.Signature
|
||||||
|
} else {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("no valid signature provided"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := poseidon.HashBytes(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("could not hash proving key"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
address := h.Bytes()
|
||||||
|
|
||||||
|
input := []byte{}
|
||||||
|
input = append(input, frame.Filter...)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, frame.FrameNumber)
|
||||||
|
input = binary.BigEndian.AppendUint64(input, uint64(frame.Timestamp))
|
||||||
|
input = binary.BigEndian.AppendUint32(input, frame.Difficulty)
|
||||||
|
input = append(input, address...)
|
||||||
|
input = append(input, frame.Input...)
|
||||||
|
|
||||||
|
if len(frame.Input) < 516 {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := sha3.Sum256(input)
|
||||||
|
v := vdf.New(frame.Difficulty, b)
|
||||||
|
proof := [516]byte{}
|
||||||
|
copy(proof[:], frame.Output)
|
||||||
|
|
||||||
|
// TODO: make this configurable for signing algorithms that allow
|
||||||
|
// user-supplied hash functions
|
||||||
|
switch pubkeyType {
|
||||||
|
case keys.KeyTypeEd448:
|
||||||
|
if len(pubkey) != 57 || len(signature) != 114 || !ed448.VerifyAny(
|
||||||
|
pubkey,
|
||||||
|
append(append([]byte{}, b[:]...), frame.Output...),
|
||||||
|
signature,
|
||||||
|
crypto.Hash(0),
|
||||||
|
) {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid signature for issuer"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !v.Verify(proof) {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("invalid proof"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
previousSelectorBytes := [516]byte{}
|
||||||
|
copy(previousSelectorBytes[:], frame.Input[:516])
|
||||||
|
|
||||||
|
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "verify clock frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
selector := new(big.Int).SetBytes(frame.ParentSelector)
|
||||||
|
if parent.Cmp(selector) != 0 {
|
||||||
|
return errors.Wrap(
|
||||||
|
errors.New("selector did not match input"),
|
||||||
|
"verify clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
28
node/crypto/wesolowski_frame_prover_test.go
Normal file
28
node/crypto/wesolowski_frame_prover_test.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package crypto_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMasterProve(t *testing.T) {
|
||||||
|
l, _ := zap.NewProduction()
|
||||||
|
w := crypto.NewWesolowskiFrameProver(l)
|
||||||
|
m, err := w.CreateMasterGenesisFrame([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
}, bytes.Repeat([]byte{0x00}, 516), 10000)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
next, err := w.ProveMasterClockFrame(m, time.Now().UnixMilli(), 10000)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = w.VerifyMasterClockFrame(next)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
@ -667,7 +667,10 @@ func MaterializeApplicationFromFrame(
|
|||||||
lastStateCount := frame.FrameNumber -
|
lastStateCount := frame.FrameNumber -
|
||||||
inProgress.ActiveParticipants[len(inProgress.ActiveParticipants)-1].FrameNumber
|
inProgress.ActiveParticipants[len(inProgress.ActiveParticipants)-1].FrameNumber
|
||||||
if !setCount || (lastStateCount < stateCount && lastStateCount > 20) {
|
if !setCount || (lastStateCount < stateCount && lastStateCount > 20) {
|
||||||
stateCount = lastStateCount - 20
|
stateCount = lastStateCount
|
||||||
|
if stateCount >= 10 {
|
||||||
|
stateCount -= 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,9 +763,26 @@ func MaterializeApplicationFromFrame(
|
|||||||
func (a *CeremonyApplication) ApplyTransition(
|
func (a *CeremonyApplication) ApplyTransition(
|
||||||
currentFrameNumber uint64,
|
currentFrameNumber uint64,
|
||||||
transition *protobufs.CeremonyLobbyStateTransition,
|
transition *protobufs.CeremonyLobbyStateTransition,
|
||||||
) (*CeremonyApplication, error) {
|
skipFailures bool,
|
||||||
|
) (
|
||||||
|
*CeremonyApplication,
|
||||||
|
*protobufs.CeremonyLobbyStateTransition,
|
||||||
|
*protobufs.CeremonyLobbyStateTransition,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
finalizedTransition := &protobufs.CeremonyLobbyStateTransition{
|
||||||
|
TypeUrls: []string{},
|
||||||
|
TransitionInputs: [][]byte{},
|
||||||
|
}
|
||||||
|
skippedTransition := &protobufs.CeremonyLobbyStateTransition{
|
||||||
|
TypeUrls: []string{},
|
||||||
|
TransitionInputs: [][]byte{},
|
||||||
|
}
|
||||||
switch a.LobbyState {
|
switch a.LobbyState {
|
||||||
case CEREMONY_APPLICATION_STATE_OPEN:
|
case CEREMONY_APPLICATION_STATE_OPEN:
|
||||||
|
if a.StateCount > currentFrameNumber {
|
||||||
|
a.StateCount = 0
|
||||||
|
}
|
||||||
a.StateCount++
|
a.StateCount++
|
||||||
|
|
||||||
for i, url := range transition.TypeUrls {
|
for i, url := range transition.TypeUrls {
|
||||||
@ -771,34 +791,75 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
join := &protobufs.CeremonyLobbyJoin{}
|
join := &protobufs.CeremonyLobbyJoin{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], join)
|
err := proto.Unmarshal(transition.TransitionInputs[i], join)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber < join.FrameNumber {
|
if currentFrameNumber < join.FrameNumber {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("too recent join"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
|
errors.New("too recent join"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
)
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber-join.FrameNumber > 10 {
|
if currentFrameNumber-join.FrameNumber > 10 {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("outdated join"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
)
|
errors.New("outdated join"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applyLobbyJoin(join); err != nil {
|
if err = a.applyLobbyJoin(join); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
default:
|
default:
|
||||||
return a, nil
|
if !skipFailures {
|
||||||
|
return a, nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.StateCount > 10 {
|
if a.StateCount > 10 {
|
||||||
if len(a.LobbyJoins) == 0 {
|
if len(a.LobbyJoins) == 0 {
|
||||||
return a, nil
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
a.LobbyState = CEREMONY_APPLICATION_STATE_IN_PROGRESS
|
a.LobbyState = CEREMONY_APPLICATION_STATE_IN_PROGRESS
|
||||||
@ -806,14 +867,17 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
a.RoundCount = 1
|
a.RoundCount = 1
|
||||||
|
|
||||||
if err := a.finalizeParticipantSet(); err != nil {
|
if err := a.finalizeParticipantSet(); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
}
|
}
|
||||||
|
|
||||||
a.LobbyJoins = []*protobufs.CeremonyLobbyJoin{}
|
a.LobbyJoins = []*protobufs.CeremonyLobbyJoin{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a, nil
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
case CEREMONY_APPLICATION_STATE_IN_PROGRESS:
|
case CEREMONY_APPLICATION_STATE_IN_PROGRESS:
|
||||||
|
if a.StateCount > currentFrameNumber {
|
||||||
|
a.StateCount = 0
|
||||||
|
}
|
||||||
a.StateCount++
|
a.StateCount++
|
||||||
for i, url := range transition.TypeUrls {
|
for i, url := range transition.TypeUrls {
|
||||||
switch url {
|
switch url {
|
||||||
@ -821,61 +885,149 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
seenProverAtt := &protobufs.CeremonySeenProverAttestation{}
|
seenProverAtt := &protobufs.CeremonySeenProverAttestation{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], seenProverAtt)
|
err := proto.Unmarshal(transition.TransitionInputs[i], seenProverAtt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber < seenProverAtt.LastSeenFrame {
|
if currentFrameNumber < seenProverAtt.LastSeenFrame {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("too recent attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
|
errors.New("too recent attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
)
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber-seenProverAtt.LastSeenFrame > 10 {
|
if currentFrameNumber-seenProverAtt.LastSeenFrame > 10 {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("outdated attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
)
|
errors.New("outdated attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applySeenProverAttestation(seenProverAtt); err != nil {
|
if err = a.applySeenProverAttestation(seenProverAtt); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
case protobufs.CeremonyDroppedProverAttestationType:
|
case protobufs.CeremonyDroppedProverAttestationType:
|
||||||
droppedProverAtt := &protobufs.CeremonyDroppedProverAttestation{}
|
droppedProverAtt := &protobufs.CeremonyDroppedProverAttestation{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], droppedProverAtt)
|
err := proto.Unmarshal(transition.TransitionInputs[i], droppedProverAtt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber < droppedProverAtt.LastSeenFrame {
|
if currentFrameNumber < droppedProverAtt.LastSeenFrame {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("too recent attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
|
errors.New("too recent attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
)
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber-droppedProverAtt.LastSeenFrame > 10 {
|
if currentFrameNumber-droppedProverAtt.LastSeenFrame > 10 {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("outdated attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
)
|
errors.New("outdated attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applyDroppedProverAttestation(droppedProverAtt); err != nil {
|
if err = a.applyDroppedProverAttestation(droppedProverAtt); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
case protobufs.CeremonyTranscriptCommitType:
|
case protobufs.CeremonyTranscriptCommitType:
|
||||||
transcriptCommit := &protobufs.CeremonyTranscriptCommit{}
|
transcriptCommit := &protobufs.CeremonyTranscriptCommit{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], transcriptCommit)
|
err := proto.Unmarshal(transition.TransitionInputs[i], transcriptCommit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applyTranscriptCommit(transcriptCommit); err != nil {
|
if err = a.applyTranscriptCommit(transcriptCommit); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
default:
|
default:
|
||||||
return a, nil
|
if !skipFailures {
|
||||||
|
return a, nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,7 +1050,7 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
[]*protobufs.CeremonySeenProverAttestation{}
|
[]*protobufs.CeremonySeenProverAttestation{}
|
||||||
a.TranscriptRoundAdvanceCommits =
|
a.TranscriptRoundAdvanceCommits =
|
||||||
[]*protobufs.CeremonyAdvanceRound{}
|
[]*protobufs.CeremonyAdvanceRound{}
|
||||||
return a, nil
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
attLimit := 1<<a.RoundCount - 1
|
attLimit := 1<<a.RoundCount - 1
|
||||||
@ -949,8 +1101,11 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
[]*protobufs.CeremonyAdvanceRound{}
|
[]*protobufs.CeremonyAdvanceRound{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a, nil
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
case CEREMONY_APPLICATION_STATE_FINALIZING:
|
case CEREMONY_APPLICATION_STATE_FINALIZING:
|
||||||
|
if a.StateCount > currentFrameNumber {
|
||||||
|
a.StateCount = 0
|
||||||
|
}
|
||||||
a.StateCount++
|
a.StateCount++
|
||||||
for i, url := range transition.TypeUrls {
|
for i, url := range transition.TypeUrls {
|
||||||
switch url {
|
switch url {
|
||||||
@ -958,67 +1113,155 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
seenProverAtt := &protobufs.CeremonySeenProverAttestation{}
|
seenProverAtt := &protobufs.CeremonySeenProverAttestation{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], seenProverAtt)
|
err := proto.Unmarshal(transition.TransitionInputs[i], seenProverAtt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber < seenProverAtt.LastSeenFrame {
|
if currentFrameNumber < seenProverAtt.LastSeenFrame {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("too recent attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
|
errors.New("too recent attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
)
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber-seenProverAtt.LastSeenFrame > 10 {
|
if currentFrameNumber-seenProverAtt.LastSeenFrame > 10 {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("outdated attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
)
|
errors.New("outdated attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applySeenProverAttestation(seenProverAtt); err != nil {
|
if err = a.applySeenProverAttestation(seenProverAtt); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
case protobufs.CeremonyDroppedProverAttestationType:
|
case protobufs.CeremonyDroppedProverAttestationType:
|
||||||
droppedProverAtt := &protobufs.CeremonyDroppedProverAttestation{}
|
droppedProverAtt := &protobufs.CeremonyDroppedProverAttestation{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], droppedProverAtt)
|
err := proto.Unmarshal(transition.TransitionInputs[i], droppedProverAtt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber < droppedProverAtt.LastSeenFrame {
|
if currentFrameNumber < droppedProverAtt.LastSeenFrame {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("too recent attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
|
errors.New("too recent attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
)
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentFrameNumber-droppedProverAtt.LastSeenFrame > 10 {
|
if currentFrameNumber-droppedProverAtt.LastSeenFrame > 10 {
|
||||||
return nil, errors.Wrap(
|
if !skipFailures {
|
||||||
errors.New("outdated attestation"), "apply transition",
|
return nil, nil, nil, errors.Wrap(
|
||||||
)
|
errors.New("outdated attestation"), "apply transition",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applyDroppedProverAttestation(droppedProverAtt); err != nil {
|
if err = a.applyDroppedProverAttestation(droppedProverAtt); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
case protobufs.CeremonyTranscriptShareType:
|
case protobufs.CeremonyTranscriptShareType:
|
||||||
transcriptShare := &protobufs.CeremonyTranscriptShare{}
|
transcriptShare := &protobufs.CeremonyTranscriptShare{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], transcriptShare)
|
err := proto.Unmarshal(transition.TransitionInputs[i], transcriptShare)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applyTranscriptShare(transcriptShare); err != nil {
|
if err = a.applyTranscriptShare(transcriptShare); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
default:
|
default:
|
||||||
return a, nil
|
if !skipFailures {
|
||||||
|
return a, nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.TranscriptShares) == len(a.ActiveParticipants) {
|
if len(a.TranscriptShares) == len(a.ActiveParticipants) {
|
||||||
if err := a.finalizeTranscript(); err != nil {
|
if err := a.finalizeTranscript(); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
}
|
}
|
||||||
|
|
||||||
a.LobbyState = CEREMONY_APPLICATION_STATE_VALIDATING
|
a.LobbyState = CEREMONY_APPLICATION_STATE_VALIDATING
|
||||||
@ -1027,7 +1270,7 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
[]*protobufs.CeremonyDroppedProverAttestation{}
|
[]*protobufs.CeremonyDroppedProverAttestation{}
|
||||||
a.LatestSeenProverAttestations =
|
a.LatestSeenProverAttestations =
|
||||||
[]*protobufs.CeremonySeenProverAttestation{}
|
[]*protobufs.CeremonySeenProverAttestation{}
|
||||||
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldReset := false
|
shouldReset := false
|
||||||
@ -1048,7 +1291,7 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.StateCount > 10 {
|
if a.StateCount > 100 {
|
||||||
shouldReset = true
|
shouldReset = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,8 +1324,11 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
[]*protobufs.CeremonyTranscriptShare{}
|
[]*protobufs.CeremonyTranscriptShare{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a, nil
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
case CEREMONY_APPLICATION_STATE_VALIDATING:
|
case CEREMONY_APPLICATION_STATE_VALIDATING:
|
||||||
|
if a.StateCount > currentFrameNumber {
|
||||||
|
a.StateCount = 0
|
||||||
|
}
|
||||||
a.StateCount++
|
a.StateCount++
|
||||||
for i, url := range transition.TypeUrls {
|
for i, url := range transition.TypeUrls {
|
||||||
switch url {
|
switch url {
|
||||||
@ -1090,20 +1336,47 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
transcript := &protobufs.CeremonyTranscript{}
|
transcript := &protobufs.CeremonyTranscript{}
|
||||||
err := proto.Unmarshal(transition.TransitionInputs[i], transcript)
|
err := proto.Unmarshal(transition.TransitionInputs[i], transcript)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.applyTranscript(transcript); err != nil {
|
if err = a.applyTranscript(transcript); err != nil {
|
||||||
return nil, errors.Wrap(err, "apply transition")
|
if !skipFailures {
|
||||||
|
return nil, nil, nil, errors.Wrap(err, "apply transition")
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalizedTransition.TypeUrls = append(
|
||||||
|
finalizedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
finalizedTransition.TransitionInputs = append(
|
||||||
|
finalizedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
|
||||||
a.StateCount = 0
|
a.StateCount = 0
|
||||||
default:
|
default:
|
||||||
return a, nil
|
if !skipFailures {
|
||||||
|
return a, nil, nil, nil
|
||||||
|
}
|
||||||
|
skippedTransition.TypeUrls = append(
|
||||||
|
skippedTransition.TypeUrls,
|
||||||
|
url,
|
||||||
|
)
|
||||||
|
skippedTransition.TransitionInputs = append(
|
||||||
|
skippedTransition.TransitionInputs,
|
||||||
|
transition.TransitionInputs[i],
|
||||||
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldReset := false
|
shouldReset := false
|
||||||
if a.StateCount > 100 {
|
if a.StateCount > 300 {
|
||||||
shouldReset = true
|
shouldReset = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1160,9 +1433,9 @@ func (a *CeremonyApplication) ApplyTransition(
|
|||||||
a.FinalCommits = []*protobufs.CeremonyTranscriptCommit{}
|
a.FinalCommits = []*protobufs.CeremonyTranscriptCommit{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a, nil
|
return a, finalizedTransition, skippedTransition, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.Wrap(ErrInvalidStateTransition, "apply transition")
|
return nil, nil, nil, errors.Wrap(ErrInvalidStateTransition, "apply transition")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
)
|
)
|
||||||
@ -79,43 +78,30 @@ func (a *CeremonyApplication) applyTranscriptShare(
|
|||||||
return errors.Wrap(err, "apply transcript share")
|
return errors.Wrap(err, "apply transcript share")
|
||||||
}
|
}
|
||||||
|
|
||||||
eg := errgroup.Group{}
|
|
||||||
eg.SetLimit(100)
|
|
||||||
|
|
||||||
for i, g1 := range a.LatestTranscript.G1Powers {
|
for i, g1 := range a.LatestTranscript.G1Powers {
|
||||||
i := i
|
i := i
|
||||||
g1 := g1
|
g1 := g1
|
||||||
eg.Go(func() error {
|
if _, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
||||||
if _, err := curves.BLS48581G1().Point.FromAffineCompressed(
|
g1.KeyValue,
|
||||||
g1.KeyValue,
|
); err != nil {
|
||||||
); err != nil {
|
return errors.Wrap(
|
||||||
return errors.Wrap(
|
errors.Wrap(err, fmt.Sprintf("invalid g1 at position %d", i)),
|
||||||
errors.Wrap(err, fmt.Sprintf("invalid g1 at position %d", i)),
|
"apply transcript share",
|
||||||
"apply transcript share",
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, g2 := range a.LatestTranscript.G2Powers {
|
for i, g2 := range a.LatestTranscript.G2Powers {
|
||||||
i := i
|
i := i
|
||||||
g2 := g2
|
g2 := g2
|
||||||
eg.Go(func() error {
|
if _, err := curves.BLS48581G2().Point.FromAffineCompressed(
|
||||||
if _, err := curves.BLS48581G2().Point.FromAffineCompressed(
|
g2.KeyValue,
|
||||||
g2.KeyValue,
|
); err != nil {
|
||||||
); err != nil {
|
return errors.Wrap(
|
||||||
return errors.Wrap(
|
errors.Wrap(err, fmt.Sprintf("invalid g2 at position %d", i)),
|
||||||
errors.Wrap(err, fmt.Sprintf("invalid g2 at position %d", i)),
|
"apply transcript share",
|
||||||
"apply transcript share",
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := eg.Wait(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exists := false
|
exists := false
|
@ -100,26 +100,26 @@ func TestCeremonyTransitions(t *testing.T) {
|
|||||||
joinBytes, err := proto.Marshal(join)
|
joinBytes, err := proto.Marshal(join)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
a, err = a.ApplyTransition(0, &protobufs.CeremonyLobbyStateTransition{
|
a, _, _, err = a.ApplyTransition(0, &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{protobufs.CeremonyLobbyJoinType},
|
TypeUrls: []string{protobufs.CeremonyLobbyJoinType},
|
||||||
TransitionInputs: [][]byte{joinBytes},
|
TransitionInputs: [][]byte{joinBytes},
|
||||||
})
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN)
|
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN)
|
||||||
|
|
||||||
for i := uint64(0); i < 10; i++ {
|
for i := uint64(0); i < 10; i++ {
|
||||||
a, err = a.ApplyTransition(i+1, &protobufs.CeremonyLobbyStateTransition{
|
a, _, _, err = a.ApplyTransition(i+1, &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{},
|
TypeUrls: []string{},
|
||||||
TransitionInputs: [][]byte{},
|
TransitionInputs: [][]byte{},
|
||||||
})
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN)
|
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err = a.ApplyTransition(12, &protobufs.CeremonyLobbyStateTransition{
|
a, _, _, err = a.ApplyTransition(12, &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{},
|
TypeUrls: []string{},
|
||||||
TransitionInputs: [][]byte{},
|
TransitionInputs: [][]byte{},
|
||||||
})
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_IN_PROGRESS)
|
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_IN_PROGRESS)
|
||||||
require.True(t, bytes.Equal(
|
require.True(t, bytes.Equal(
|
||||||
@ -165,10 +165,10 @@ func TestCeremonyTransitions(t *testing.T) {
|
|||||||
advanceRoundBytes, err := proto.Marshal(advanceRound)
|
advanceRoundBytes, err := proto.Marshal(advanceRound)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
a, err = a.ApplyTransition(13, &protobufs.CeremonyLobbyStateTransition{
|
a, _, _, err = a.ApplyTransition(13, &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{protobufs.CeremonyTranscriptCommitType},
|
TypeUrls: []string{protobufs.CeremonyTranscriptCommitType},
|
||||||
TransitionInputs: [][]byte{advanceRoundBytes},
|
TransitionInputs: [][]byte{advanceRoundBytes},
|
||||||
})
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_FINALIZING)
|
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_FINALIZING)
|
||||||
|
|
||||||
@ -209,10 +209,10 @@ func TestCeremonyTransitions(t *testing.T) {
|
|||||||
shareBytes, err := proto.Marshal(transcriptShare)
|
shareBytes, err := proto.Marshal(transcriptShare)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
a, err = a.ApplyTransition(14, &protobufs.CeremonyLobbyStateTransition{
|
a, _, _, err = a.ApplyTransition(14, &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{protobufs.CeremonyTranscriptShareType},
|
TypeUrls: []string{protobufs.CeremonyTranscriptShareType},
|
||||||
TransitionInputs: [][]byte{shareBytes},
|
TransitionInputs: [][]byte{shareBytes},
|
||||||
})
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_VALIDATING)
|
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_VALIDATING)
|
||||||
|
|
||||||
@ -272,10 +272,10 @@ func TestCeremonyTransitions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
transcriptBytes, err := proto.Marshal(updatedTranscript)
|
transcriptBytes, err := proto.Marshal(updatedTranscript)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
a, err = a.ApplyTransition(15, &protobufs.CeremonyLobbyStateTransition{
|
a, _, _, err = a.ApplyTransition(15, &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{protobufs.CeremonyTranscriptType},
|
TypeUrls: []string{protobufs.CeremonyTranscriptType},
|
||||||
TransitionInputs: [][]byte{transcriptBytes},
|
TransitionInputs: [][]byte{transcriptBytes},
|
||||||
})
|
}, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN)
|
require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN)
|
||||||
bi, err := poseidon.HashBytes(proverPubKey)
|
bi, err := poseidon.HashBytes(proverPubKey)
|
@ -12,8 +12,8 @@ import (
|
|||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
bls48581 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581"
|
bls48581 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/ot/base/simplest"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/ot/base/simplest"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/channel"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony/application"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPairings(t *testing.T) {
|
func TestPairings(t *testing.T) {
|
||||||
@ -329,7 +329,7 @@ func TestCompositeConstructionOfBLS(t *testing.T) {
|
|||||||
x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey)
|
x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey)
|
||||||
x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey)
|
x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey)
|
||||||
|
|
||||||
senderResult := crypto.SenderX3DH(
|
senderResult := channel.SenderX3DH(
|
||||||
x448SendingIdentityPrivateKey,
|
x448SendingIdentityPrivateKey,
|
||||||
x448SendingEphemeralPrivateKey,
|
x448SendingEphemeralPrivateKey,
|
||||||
x448ReceivingIdentityKey,
|
x448ReceivingIdentityKey,
|
||||||
@ -337,7 +337,7 @@ func TestCompositeConstructionOfBLS(t *testing.T) {
|
|||||||
96,
|
96,
|
||||||
)
|
)
|
||||||
|
|
||||||
receiverResult := crypto.ReceiverX3DH(
|
receiverResult := channel.ReceiverX3DH(
|
||||||
x448ReceivingIdentityPrivateKey,
|
x448ReceivingIdentityPrivateKey,
|
||||||
x448ReceivingSignedPrePrivateKey,
|
x448ReceivingSignedPrePrivateKey,
|
||||||
x448SendingIdentityKey,
|
x448SendingIdentityKey,
|
||||||
@ -345,7 +345,7 @@ func TestCompositeConstructionOfBLS(t *testing.T) {
|
|||||||
96,
|
96,
|
||||||
)
|
)
|
||||||
|
|
||||||
drSender, err := crypto.NewDoubleRatchetParticipant(
|
drSender, err := channel.NewDoubleRatchetParticipant(
|
||||||
senderResult[:32],
|
senderResult[:32],
|
||||||
senderResult[32:64],
|
senderResult[32:64],
|
||||||
senderResult[64:],
|
senderResult[64:],
|
||||||
@ -357,7 +357,7 @@ func TestCompositeConstructionOfBLS(t *testing.T) {
|
|||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
drReceiver, err := crypto.NewDoubleRatchetParticipant(
|
drReceiver, err := channel.NewDoubleRatchetParticipant(
|
||||||
receiverResult[:32],
|
receiverResult[:32],
|
||||||
receiverResult[32:64],
|
receiverResult[32:64],
|
||||||
receiverResult[64:],
|
receiverResult[64:],
|
@ -4,8 +4,12 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -18,15 +22,19 @@ import (
|
|||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/consensus/ceremony"
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/ceremony"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/consensus/time"
|
||||||
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/kzg"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony/application"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
"source.quilibrium.com/quilibrium/monorepo/node/store"
|
||||||
|
"source.quilibrium.com/quilibrium/monorepo/node/tries"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CeremonyExecutionEngine struct {
|
type CeremonyExecutionEngine struct {
|
||||||
@ -41,6 +49,7 @@ type CeremonyExecutionEngine struct {
|
|||||||
provingKey crypto.Signer
|
provingKey crypto.Signer
|
||||||
proverPublicKey []byte
|
proverPublicKey []byte
|
||||||
provingKeyAddress []byte
|
provingKeyAddress []byte
|
||||||
|
inclusionProver qcrypto.InclusionProver
|
||||||
participantMx sync.Mutex
|
participantMx sync.Mutex
|
||||||
peerChannels map[string]*p2p.PublicP2PChannel
|
peerChannels map[string]*p2p.PublicP2PChannel
|
||||||
activeSecrets []curves.Scalar
|
activeSecrets []curves.Scalar
|
||||||
@ -50,6 +59,7 @@ type CeremonyExecutionEngine struct {
|
|||||||
seenMessageMap map[string]bool
|
seenMessageMap map[string]bool
|
||||||
seenMessageMx sync.Mutex
|
seenMessageMx sync.Mutex
|
||||||
intrinsicFilter []byte
|
intrinsicFilter []byte
|
||||||
|
frameProver qcrypto.FrameProver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCeremonyExecutionEngine(
|
func NewCeremonyExecutionEngine(
|
||||||
@ -57,7 +67,10 @@ func NewCeremonyExecutionEngine(
|
|||||||
engineConfig *config.EngineConfig,
|
engineConfig *config.EngineConfig,
|
||||||
keyManager keys.KeyManager,
|
keyManager keys.KeyManager,
|
||||||
pubSub p2p.PubSub,
|
pubSub p2p.PubSub,
|
||||||
|
frameProver qcrypto.FrameProver,
|
||||||
|
inclusionProver qcrypto.InclusionProver,
|
||||||
clockStore store.ClockStore,
|
clockStore store.ClockStore,
|
||||||
|
masterTimeReel *time.MasterTimeReel,
|
||||||
keyStore store.KeyStore,
|
keyStore store.KeyStore,
|
||||||
) *CeremonyExecutionEngine {
|
) *CeremonyExecutionEngine {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
@ -74,6 +87,31 @@ func NewCeremonyExecutionEngine(
|
|||||||
p2p.GetBloomFilterIndices(application.CEREMONY_ADDRESS, 65536, 24)...,
|
p2p.GetBloomFilterIndices(application.CEREMONY_ADDRESS, 65536, 24)...,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_, _, err = clockStore.GetDataClockFrame(intrinsicFilter, 0)
|
||||||
|
var origin []byte
|
||||||
|
var inclusionProof *qcrypto.InclusionAggregateProof
|
||||||
|
var proverKeys [][]byte
|
||||||
|
|
||||||
|
if err != nil && errors.Is(err, store.ErrNotFound) {
|
||||||
|
origin, inclusionProof, proverKeys = CreateGenesisState(
|
||||||
|
logger,
|
||||||
|
engineConfig,
|
||||||
|
nil,
|
||||||
|
inclusionProver,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataTimeReel := time.NewDataTimeReel(
|
||||||
|
intrinsicFilter,
|
||||||
|
logger,
|
||||||
|
clockStore,
|
||||||
|
engineConfig,
|
||||||
|
frameProver,
|
||||||
|
origin,
|
||||||
|
inclusionProof,
|
||||||
|
proverKeys,
|
||||||
|
)
|
||||||
|
|
||||||
clock := ceremony.NewCeremonyDataClockConsensusEngine(
|
clock := ceremony.NewCeremonyDataClockConsensusEngine(
|
||||||
engineConfig,
|
engineConfig,
|
||||||
logger,
|
logger,
|
||||||
@ -81,6 +119,10 @@ func NewCeremonyExecutionEngine(
|
|||||||
clockStore,
|
clockStore,
|
||||||
keyStore,
|
keyStore,
|
||||||
pubSub,
|
pubSub,
|
||||||
|
frameProver,
|
||||||
|
inclusionProver,
|
||||||
|
masterTimeReel,
|
||||||
|
dataTimeReel,
|
||||||
intrinsicFilter,
|
intrinsicFilter,
|
||||||
seed,
|
seed,
|
||||||
)
|
)
|
||||||
@ -93,6 +135,8 @@ func NewCeremonyExecutionEngine(
|
|||||||
clockStore: clockStore,
|
clockStore: clockStore,
|
||||||
keyStore: keyStore,
|
keyStore: keyStore,
|
||||||
pubSub: pubSub,
|
pubSub: pubSub,
|
||||||
|
inclusionProver: inclusionProver,
|
||||||
|
frameProver: frameProver,
|
||||||
participantMx: sync.Mutex{},
|
participantMx: sync.Mutex{},
|
||||||
peerChannels: map[string]*p2p.PublicP2PChannel{},
|
peerChannels: map[string]*p2p.PublicP2PChannel{},
|
||||||
alreadyPublishedShare: false,
|
alreadyPublishedShare: false,
|
||||||
@ -139,13 +183,234 @@ func (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a genesis state for the intrinsic
|
||||||
|
func CreateGenesisState(
|
||||||
|
logger *zap.Logger,
|
||||||
|
engineConfig *config.EngineConfig,
|
||||||
|
testProverKeys [][]byte,
|
||||||
|
inclusionProver qcrypto.InclusionProver,
|
||||||
|
) (
|
||||||
|
[]byte,
|
||||||
|
*qcrypto.InclusionAggregateProof,
|
||||||
|
[][]byte,
|
||||||
|
) {
|
||||||
|
seed, err := hex.DecodeString(engineConfig.GenesisSeed)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(errors.New("genesis seed is nil"))
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("creating genesis frame")
|
||||||
|
for _, l := range strings.Split(string(seed), "\n") {
|
||||||
|
logger.Info(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := sha3.Sum256(seed)
|
||||||
|
v := vdf.New(engineConfig.Difficulty, b)
|
||||||
|
|
||||||
|
v.Execute()
|
||||||
|
o := v.GetOutput()
|
||||||
|
inputMessage := o[:]
|
||||||
|
|
||||||
|
// Signatories are special, they don't have an inclusion proof because they
|
||||||
|
// have not broadcasted communication keys, but they still get contribution
|
||||||
|
// rights prior to PoMW, because they did produce meaningful work in the
|
||||||
|
// first phase:
|
||||||
|
logger.Info("encoding signatories to prover trie")
|
||||||
|
proverKeys := [][]byte{}
|
||||||
|
if len(testProverKeys) != 0 {
|
||||||
|
logger.Warn(
|
||||||
|
"TEST PROVER ENTRIES BEING ADDED, YOUR NODE WILL BE KICKED IF IN" +
|
||||||
|
" PRODUCTION",
|
||||||
|
)
|
||||||
|
proverKeys = testProverKeys
|
||||||
|
} else {
|
||||||
|
for _, s := range kzg.CeremonySignatories {
|
||||||
|
pubkey := s.ToAffineCompressed()
|
||||||
|
logger.Info("0x" + hex.EncodeToString(pubkey))
|
||||||
|
|
||||||
|
proverKeys = append(proverKeys, pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("encoding ceremony and phase one signatories")
|
||||||
|
transcript := &protobufs.CeremonyTranscript{}
|
||||||
|
for p, s := range kzg.CeremonyBLS48581G1 {
|
||||||
|
transcript.G1Powers = append(
|
||||||
|
transcript.G1Powers,
|
||||||
|
&protobufs.BLS48581G1PublicKey{
|
||||||
|
KeyValue: s.ToAffineCompressed(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logger.Info(fmt.Sprintf("encoded G1 power %d", p))
|
||||||
|
}
|
||||||
|
for p, s := range kzg.CeremonyBLS48581G2 {
|
||||||
|
transcript.G2Powers = append(
|
||||||
|
transcript.G2Powers,
|
||||||
|
&protobufs.BLS48581G2PublicKey{
|
||||||
|
KeyValue: s.ToAffineCompressed(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logger.Info(fmt.Sprintf("encoded G2 power %d", p))
|
||||||
|
}
|
||||||
|
|
||||||
|
transcript.RunningG1_256Witnesses = append(
|
||||||
|
transcript.RunningG1_256Witnesses,
|
||||||
|
&protobufs.BLS48581G1PublicKey{
|
||||||
|
KeyValue: kzg.CeremonyRunningProducts[0].ToAffineCompressed(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
transcript.RunningG2_256Powers = append(
|
||||||
|
transcript.RunningG2_256Powers,
|
||||||
|
&protobufs.BLS48581G2PublicKey{
|
||||||
|
KeyValue: kzg.CeremonyBLS48581G2[len(kzg.CeremonyBLS48581G2)-1].
|
||||||
|
ToAffineCompressed(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
outputProof := &protobufs.CeremonyLobbyStateTransition{
|
||||||
|
TypeUrls: []string{},
|
||||||
|
TransitionInputs: [][]byte{},
|
||||||
|
}
|
||||||
|
|
||||||
|
proofBytes, err := proto.Marshal(outputProof)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("encoded transcript")
|
||||||
|
logger.Info("encoding ceremony signatories into application state")
|
||||||
|
|
||||||
|
rewardTrie := &tries.RewardCritbitTrie{}
|
||||||
|
for _, s := range kzg.CeremonySignatories {
|
||||||
|
pubkey := s.ToAffineCompressed()
|
||||||
|
|
||||||
|
addr, err := poseidon.HashBytes(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrBytes := addr.Bytes()
|
||||||
|
addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...)
|
||||||
|
rewardTrie.Add(addrBytes, 0, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2024-01-03: 1.2.0
|
||||||
|
d, err := os.ReadFile("./retroactive_peers.json")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type peerData struct {
|
||||||
|
PeerId string `json:"peer_id"`
|
||||||
|
TokenBalance uint64 `json:"token_balance"`
|
||||||
|
}
|
||||||
|
type rewards struct {
|
||||||
|
Rewards []peerData `json:"rewards"`
|
||||||
|
}
|
||||||
|
|
||||||
|
retroEntries := &rewards{}
|
||||||
|
err = json.Unmarshal(d, retroEntries)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("adding retroactive peer reward info")
|
||||||
|
for _, s := range retroEntries.Rewards {
|
||||||
|
peerId := s.PeerId
|
||||||
|
peerBytes, err := base64.StdEncoding.DecodeString(peerId)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := poseidon.HashBytes(peerBytes)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrBytes := addr.Bytes()
|
||||||
|
addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...)
|
||||||
|
rewardTrie.Add(addrBytes, 0, s.TokenBalance)
|
||||||
|
}
|
||||||
|
|
||||||
|
trieBytes, err := rewardTrie.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ceremonyLobbyState := &protobufs.CeremonyLobbyState{
|
||||||
|
LobbyState: 0,
|
||||||
|
CeremonyState: &protobufs.CeremonyLobbyState_CeremonyOpenState{
|
||||||
|
CeremonyOpenState: &protobufs.CeremonyOpenState{
|
||||||
|
JoinedParticipants: []*protobufs.CeremonyLobbyJoin{},
|
||||||
|
PreferredParticipants: []*protobufs.Ed448PublicKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LatestTranscript: transcript,
|
||||||
|
RewardTrie: trieBytes,
|
||||||
|
}
|
||||||
|
outputBytes, err := proto.Marshal(ceremonyLobbyState)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
executionOutput := &protobufs.IntrinsicExecutionOutput{
|
||||||
|
Address: application.CEREMONY_ADDRESS,
|
||||||
|
Output: outputBytes,
|
||||||
|
Proof: proofBytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := proto.Marshal(executionOutput)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("encoded execution output")
|
||||||
|
|
||||||
|
digest := sha3.NewShake256()
|
||||||
|
_, err = digest.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expand := make([]byte, 1024)
|
||||||
|
_, err = digest.Read(expand)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("proving execution output for inclusion")
|
||||||
|
commitment, err := inclusionProver.Commit(
|
||||||
|
expand,
|
||||||
|
protobufs.IntrinsicExecutionOutputType,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("creating kzg proof")
|
||||||
|
proof, err := inclusionProver.ProveAggregate(
|
||||||
|
[]*qcrypto.InclusionCommitment{
|
||||||
|
commitment,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("finalizing execution proof")
|
||||||
|
|
||||||
|
return inputMessage, proof, proverKeys
|
||||||
|
}
|
||||||
|
|
||||||
// Start implements ExecutionEngine
|
// Start implements ExecutionEngine
|
||||||
func (e *CeremonyExecutionEngine) Start() <-chan error {
|
func (e *CeremonyExecutionEngine) Start() <-chan error {
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
|
|
||||||
e.logger.Info("ceremony data loaded", zap.Binary(
|
e.logger.Info("ceremony data loaded", zap.Binary(
|
||||||
"g2_power",
|
"g2_power",
|
||||||
qcrypto.CeremonyBLS48581G2[1].ToAffineCompressed(),
|
kzg.CeremonyBLS48581G2[1].ToAffineCompressed(),
|
||||||
))
|
))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -203,7 +468,7 @@ func (e *CeremonyExecutionEngine) ProcessMessage(
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := frame.VerifyDataClockFrame(); err != nil {
|
if err := e.frameProver.VerifyDataClockFrame(frame); err != nil {
|
||||||
return nil, errors.Wrap(err, "process message")
|
return nil, errors.Wrap(err, "process message")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +486,6 @@ func (e *CeremonyExecutionEngine) ProcessMessage(
|
|||||||
case protobufs.CeremonyTranscriptShareType:
|
case protobufs.CeremonyTranscriptShareType:
|
||||||
fallthrough
|
fallthrough
|
||||||
case protobufs.CeremonyTranscriptType:
|
case protobufs.CeremonyTranscriptType:
|
||||||
frame := e.activeClockFrame
|
|
||||||
hash := sha3.Sum256(any.Value)
|
hash := sha3.Sum256(any.Value)
|
||||||
if any.TypeUrl == protobufs.CeremonyTranscriptType {
|
if any.TypeUrl == protobufs.CeremonyTranscriptType {
|
||||||
e.seenMessageMx.Lock()
|
e.seenMessageMx.Lock()
|
||||||
@ -237,10 +501,6 @@ func (e *CeremonyExecutionEngine) ProcessMessage(
|
|||||||
e.seenMessageMx.Unlock()
|
e.seenMessageMx.Unlock()
|
||||||
}
|
}
|
||||||
if e.clock.IsInProverTrie(e.proverPublicKey) {
|
if e.clock.IsInProverTrie(e.proverPublicKey) {
|
||||||
app, err := application.MaterializeApplicationFromFrame(frame)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "process message")
|
|
||||||
}
|
|
||||||
proposedTransition := &protobufs.CeremonyLobbyStateTransition{
|
proposedTransition := &protobufs.CeremonyLobbyStateTransition{
|
||||||
TypeUrls: []string{any.TypeUrl},
|
TypeUrls: []string{any.TypeUrl},
|
||||||
TransitionInputs: [][]byte{
|
TransitionInputs: [][]byte{
|
||||||
@ -248,11 +508,6 @@ func (e *CeremonyExecutionEngine) ProcessMessage(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = app.ApplyTransition(frame.FrameNumber, proposedTransition)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "process message")
|
|
||||||
}
|
|
||||||
|
|
||||||
any := &anypb.Any{}
|
any := &anypb.Any{}
|
||||||
if err := any.MarshalFrom(proposedTransition); err != nil {
|
if err := any.MarshalFrom(proposedTransition); err != nil {
|
||||||
return nil, errors.Wrap(err, "process message")
|
return nil, errors.Wrap(err, "process message")
|
||||||
@ -293,14 +548,13 @@ func (e *CeremonyExecutionEngine) ProcessMessage(
|
|||||||
func (e *CeremonyExecutionEngine) RunWorker() {
|
func (e *CeremonyExecutionEngine) RunWorker() {
|
||||||
frameChan := e.clock.GetFrameChannel()
|
frameChan := e.clock.GetFrameChannel()
|
||||||
for {
|
for {
|
||||||
frameFromBuffer := <-frameChan
|
frame := <-frameChan
|
||||||
frame := e.clock.GetFrame()
|
|
||||||
e.activeClockFrame = frame
|
e.activeClockFrame = frame
|
||||||
e.logger.Info(
|
e.logger.Info(
|
||||||
"evaluating next frame",
|
"evaluating next frame",
|
||||||
zap.Int(
|
zap.Uint64(
|
||||||
"last_run_took_frames",
|
"frame_number",
|
||||||
int(frame.FrameNumber)-int(frameFromBuffer.FrameNumber),
|
frame.FrameNumber,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
app, err := application.MaterializeApplicationFromFrame(frame)
|
app, err := application.MaterializeApplicationFromFrame(frame)
|
||||||
@ -519,9 +773,7 @@ func (e *CeremonyExecutionEngine) RunWorker() {
|
|||||||
}
|
}
|
||||||
case application.CEREMONY_APPLICATION_STATE_VALIDATING:
|
case application.CEREMONY_APPLICATION_STATE_VALIDATING:
|
||||||
e.logger.Info("round contribution validating")
|
e.logger.Info("round contribution validating")
|
||||||
// Do a best effort to clear – Go's GC is noisy and unenforceable, but
|
e.alreadyPublishedShare = false
|
||||||
// this should at least mark it as dead space
|
|
||||||
e.activeSecrets = []curves.Scalar{}
|
|
||||||
for _, c := range e.peerChannels {
|
for _, c := range e.peerChannels {
|
||||||
c.Close()
|
c.Close()
|
||||||
}
|
}
|
||||||
@ -1134,7 +1386,7 @@ func (e *CeremonyExecutionEngine) VerifyExecution(
|
|||||||
return errors.Wrap(err, "verify execution")
|
return errors.Wrap(err, "verify execution")
|
||||||
}
|
}
|
||||||
|
|
||||||
a, err = a.ApplyTransition(frame.FrameNumber, transition)
|
a, _, _, err = a.ApplyTransition(frame.FrameNumber, transition, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "verify execution")
|
return errors.Wrap(err, "verify execution")
|
||||||
}
|
}
|
21
node/go.mod
21
node/go.mod
@ -25,6 +25,11 @@ require (
|
|||||||
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000
|
source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/DataDog/zstd v1.4.5 // indirect
|
github.com/DataDog/zstd v1.4.5 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
@ -59,7 +64,7 @@ require (
|
|||||||
github.com/quic-go/qtls-go1-19 v0.3.3 // indirect
|
github.com/quic-go/qtls-go1-19 v0.3.3 // indirect
|
||||||
github.com/quic-go/qtls-go1-20 v0.2.3 // indirect
|
github.com/quic-go/qtls-go1-20 v0.2.3 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
golang.org/x/term v0.14.0
|
golang.org/x/term v0.16.0
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
@ -155,19 +160,17 @@ require (
|
|||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
|
||||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
|
||||||
go.uber.org/dig v1.17.0 // indirect
|
go.uber.org/dig v1.17.0 // indirect
|
||||||
go.uber.org/fx v1.20.0 // indirect
|
go.uber.org/fx v1.20.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.25.0
|
go.uber.org/zap v1.26.0
|
||||||
golang.org/x/crypto v0.13.0
|
golang.org/x/crypto v0.18.0
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
golang.org/x/net v0.15.0 // indirect
|
golang.org/x/net v0.20.0 // indirect
|
||||||
golang.org/x/sync v0.3.0
|
golang.org/x/sync v0.6.0
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
golang.org/x/sys v0.16.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
|
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
|
||||||
gonum.org/v1/gonum v0.11.0 // indirect
|
gonum.org/v1/gonum v0.11.0 // indirect
|
||||||
google.golang.org/grpc v1.58.2
|
google.golang.org/grpc v1.58.2
|
||||||
|
28
node/go.sum
28
node/go.sum
@ -494,8 +494,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
|||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||||
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||||
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
|
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -510,8 +510,8 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||||
@ -546,8 +546,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@ -561,8 +561,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -583,16 +583,16 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
|
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||||
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
@ -18,8 +18,8 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/app"
|
"source.quilibrium.com/quilibrium/monorepo/node/app"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
"source.quilibrium.com/quilibrium/monorepo/node/config"
|
||||||
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/kzg"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony/application"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/rpc"
|
"source.quilibrium.com/quilibrium/monorepo/node/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Loading ceremony state and starting node...")
|
fmt.Println("Loading ceremony state and starting node...")
|
||||||
qcrypto.Init()
|
kzg.Init()
|
||||||
|
|
||||||
node, err := app.NewNode(nodeConfig)
|
node, err := app.NewNode(nodeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -283,5 +283,5 @@ func printLogo() {
|
|||||||
|
|
||||||
func printVersion() {
|
func printVersion() {
|
||||||
fmt.Println(" ")
|
fmt.Println(" ")
|
||||||
fmt.Println(" Quilibrium Node - v1.2.3 – Dawn")
|
fmt.Println(" Quilibrium Node - v1.2.4 – Dawn")
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
"source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
|
"source.quilibrium.com/quilibrium/monorepo/node/crypto/channel"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
)
|
)
|
||||||
@ -18,7 +18,7 @@ import (
|
|||||||
// A simplified P2P channel – the pair of actors communicating is public
|
// A simplified P2P channel – the pair of actors communicating is public
|
||||||
// knowledge, even though the data itself is encrypted.
|
// knowledge, even though the data itself is encrypted.
|
||||||
type PublicP2PChannel struct {
|
type PublicP2PChannel struct {
|
||||||
participant *crypto.DoubleRatchetParticipant
|
participant *channel.DoubleRatchetParticipant
|
||||||
sendMap map[uint64][]byte
|
sendMap map[uint64][]byte
|
||||||
receiveMap map[uint64][]byte
|
receiveMap map[uint64][]byte
|
||||||
pubSub PubSub
|
pubSub PubSub
|
||||||
@ -58,7 +58,7 @@ func NewPublicP2PChannel(
|
|||||||
senderIdentifier...,
|
senderIdentifier...,
|
||||||
)
|
)
|
||||||
|
|
||||||
channel := &PublicP2PChannel{
|
ch := &PublicP2PChannel{
|
||||||
publicChannelClient: publicChannelClient,
|
publicChannelClient: publicChannelClient,
|
||||||
sendMap: map[uint64][]byte{},
|
sendMap: map[uint64][]byte{},
|
||||||
receiveMap: map[uint64][]byte{},
|
receiveMap: map[uint64][]byte{},
|
||||||
@ -72,19 +72,19 @@ func NewPublicP2PChannel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var participant *crypto.DoubleRatchetParticipant
|
var participant *channel.DoubleRatchetParticipant
|
||||||
if initiator {
|
if initiator {
|
||||||
sendingEphemeralPrivateKey := curve.Scalar.Random(
|
sendingEphemeralPrivateKey := curve.Scalar.Random(
|
||||||
rand.Reader,
|
rand.Reader,
|
||||||
)
|
)
|
||||||
x3dh := crypto.SenderX3DH(
|
x3dh := channel.SenderX3DH(
|
||||||
sendingIdentityPrivateKey,
|
sendingIdentityPrivateKey,
|
||||||
sendingSignedPrePrivateKey,
|
sendingSignedPrePrivateKey,
|
||||||
receivingIdentityKey,
|
receivingIdentityKey,
|
||||||
receivingSignedPreKey,
|
receivingSignedPreKey,
|
||||||
96,
|
96,
|
||||||
)
|
)
|
||||||
participant, err = crypto.NewDoubleRatchetParticipant(
|
participant, err = channel.NewDoubleRatchetParticipant(
|
||||||
x3dh[:32],
|
x3dh[:32],
|
||||||
x3dh[32:64],
|
x3dh[32:64],
|
||||||
x3dh[64:],
|
x3dh[64:],
|
||||||
@ -98,14 +98,14 @@ func NewPublicP2PChannel(
|
|||||||
return nil, errors.Wrap(err, "new public p2p channel")
|
return nil, errors.Wrap(err, "new public p2p channel")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
x3dh := crypto.SenderX3DH(
|
x3dh := channel.SenderX3DH(
|
||||||
sendingIdentityPrivateKey,
|
sendingIdentityPrivateKey,
|
||||||
sendingSignedPrePrivateKey,
|
sendingSignedPrePrivateKey,
|
||||||
receivingIdentityKey,
|
receivingIdentityKey,
|
||||||
receivingSignedPreKey,
|
receivingSignedPreKey,
|
||||||
96,
|
96,
|
||||||
)
|
)
|
||||||
participant, err = crypto.NewDoubleRatchetParticipant(
|
participant, err = channel.NewDoubleRatchetParticipant(
|
||||||
x3dh[:32],
|
x3dh[:32],
|
||||||
x3dh[32:64],
|
x3dh[32:64],
|
||||||
x3dh[64:],
|
x3dh[64:],
|
||||||
@ -120,7 +120,7 @@ func NewPublicP2PChannel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.participant = participant
|
ch.participant = participant
|
||||||
if publicChannelClient == nil {
|
if publicChannelClient == nil {
|
||||||
pubSub.Subscribe(
|
pubSub.Subscribe(
|
||||||
sendFilter,
|
sendFilter,
|
||||||
@ -130,12 +130,12 @@ func NewPublicP2PChannel(
|
|||||||
|
|
||||||
pubSub.Subscribe(
|
pubSub.Subscribe(
|
||||||
receiveFilter,
|
receiveFilter,
|
||||||
channel.handleReceive,
|
ch.handleReceive,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return channel, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PublicP2PChannel) handleReceive(message *pb.Message) error {
|
func (c *PublicP2PChannel) handleReceive(message *pb.Message) error {
|
||||||
|
@ -1,130 +1,13 @@
|
|||||||
package protobufs
|
package protobufs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/binary"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cloudflare/circl/sign/ed448"
|
|
||||||
"github.com/iden3/go-iden3-crypto/ff"
|
|
||||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf"
|
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProveMasterClockFrame(
|
func (frame *ClockFrame) GetParentAndSelector() (
|
||||||
previousFrame *ClockFrame,
|
|
||||||
difficulty uint32,
|
|
||||||
) (*ClockFrame, error) {
|
|
||||||
input := []byte{}
|
|
||||||
input = append(input, previousFrame.Filter...)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, previousFrame.FrameNumber+1)
|
|
||||||
input = binary.BigEndian.AppendUint32(input, difficulty)
|
|
||||||
input = append(input, previousFrame.Output[:]...)
|
|
||||||
|
|
||||||
b := sha3.Sum256(input)
|
|
||||||
v := vdf.New(difficulty, b)
|
|
||||||
v.Execute()
|
|
||||||
o := v.GetOutput()
|
|
||||||
|
|
||||||
timestamp := time.Now().UnixMilli()
|
|
||||||
|
|
||||||
previousSelectorBytes := [516]byte{}
|
|
||||||
copy(previousSelectorBytes[:], previousFrame.Output[:516])
|
|
||||||
|
|
||||||
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "prove clock frame")
|
|
||||||
}
|
|
||||||
|
|
||||||
frame := &ClockFrame{
|
|
||||||
Filter: previousFrame.Filter,
|
|
||||||
FrameNumber: previousFrame.FrameNumber + 1,
|
|
||||||
Timestamp: timestamp,
|
|
||||||
Difficulty: difficulty,
|
|
||||||
ParentSelector: parent.Bytes(),
|
|
||||||
Input: previousFrame.Output,
|
|
||||||
AggregateProofs: []*InclusionAggregateProof{},
|
|
||||||
Output: o[:],
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *ClockFrame) VerifyMasterClockFrame() error {
|
|
||||||
input := []byte{}
|
|
||||||
input = append(input, frame.Filter...)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, frame.FrameNumber)
|
|
||||||
input = binary.BigEndian.AppendUint32(input, frame.Difficulty)
|
|
||||||
input = append(input, frame.Input...)
|
|
||||||
|
|
||||||
if len(frame.Input) < 516 {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(frame.AggregateProofs) > 0 {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if frame.PublicKeySignature != nil {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(frame.Input) != 516 {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
b := sha3.Sum256(input)
|
|
||||||
v := vdf.New(frame.Difficulty, b)
|
|
||||||
proof := [516]byte{}
|
|
||||||
copy(proof[:], frame.Output)
|
|
||||||
|
|
||||||
if !v.Verify(proof) {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid proof"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
previousSelectorBytes := [516]byte{}
|
|
||||||
copy(previousSelectorBytes[:], frame.Input[:516])
|
|
||||||
|
|
||||||
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "verify clock frame")
|
|
||||||
}
|
|
||||||
|
|
||||||
selector := new(big.Int).SetBytes(frame.ParentSelector)
|
|
||||||
if parent.Cmp(selector) != 0 {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("selector did not match input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *ClockFrame) GetParentSelectorAndDistance(
|
|
||||||
discriminator *big.Int,
|
|
||||||
) (
|
|
||||||
*big.Int,
|
|
||||||
*big.Int,
|
*big.Int,
|
||||||
*big.Int,
|
*big.Int,
|
||||||
error,
|
error,
|
||||||
@ -134,32 +17,16 @@ func (frame *ClockFrame) GetParentSelectorAndDistance(
|
|||||||
|
|
||||||
selector, err := poseidon.HashBytes(outputBytes[:])
|
selector, err := poseidon.HashBytes(outputBytes[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, errors.Wrap(err, "get parent selector and distance")
|
return nil, nil, errors.Wrap(err, "get parent selector and distance")
|
||||||
}
|
}
|
||||||
|
|
||||||
if frame.FrameNumber == 0 {
|
if frame.FrameNumber == 0 {
|
||||||
return big.NewInt(0), big.NewInt(0), selector, nil
|
return big.NewInt(0), selector, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
parentSelector := new(big.Int).SetBytes(frame.ParentSelector)
|
parentSelector := new(big.Int).SetBytes(frame.ParentSelector)
|
||||||
|
|
||||||
var distance *big.Int
|
return parentSelector, selector, nil
|
||||||
if discriminator != nil {
|
|
||||||
l := new(big.Int).Mod(
|
|
||||||
new(big.Int).Sub(selector, discriminator),
|
|
||||||
ff.Modulus(),
|
|
||||||
)
|
|
||||||
r := new(big.Int).Mod(
|
|
||||||
new(big.Int).Sub(discriminator, selector),
|
|
||||||
ff.Modulus(),
|
|
||||||
)
|
|
||||||
distance = r
|
|
||||||
if l.Cmp(r) == 1 {
|
|
||||||
distance = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parentSelector, distance, selector, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (frame *ClockFrame) GetSelector() (*big.Int, error) {
|
func (frame *ClockFrame) GetSelector() (*big.Int, error) {
|
||||||
@ -216,196 +83,3 @@ func (frame *ClockFrame) GetAddress() ([]byte, error) {
|
|||||||
|
|
||||||
return addressBytes, nil
|
return addressBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProveDataClockFrame(
|
|
||||||
previousFrame *ClockFrame,
|
|
||||||
commitments [][]byte,
|
|
||||||
aggregateProofs []*InclusionAggregateProof,
|
|
||||||
provingKey crypto.Signer,
|
|
||||||
difficulty uint32,
|
|
||||||
) (*ClockFrame, error) {
|
|
||||||
var pubkey []byte
|
|
||||||
pubkeyType := keys.KeyTypeEd448
|
|
||||||
ed448PublicKey, ok := provingKey.Public().(ed448.PublicKey)
|
|
||||||
if ok {
|
|
||||||
pubkey = []byte(ed448PublicKey)
|
|
||||||
} else {
|
|
||||||
return nil, errors.Wrap(
|
|
||||||
errors.New("no valid signature provided"),
|
|
||||||
"prove clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
h, err := poseidon.HashBytes(pubkey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(
|
|
||||||
errors.New("could not hash proving key"),
|
|
||||||
"prove clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
address := h.Bytes()
|
|
||||||
timestamp := time.Now().UnixMilli()
|
|
||||||
input := []byte{}
|
|
||||||
input = append(input, previousFrame.Filter...)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, previousFrame.FrameNumber+1)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, uint64(timestamp))
|
|
||||||
input = binary.BigEndian.AppendUint32(input, difficulty)
|
|
||||||
input = append(input, address...)
|
|
||||||
input = append(input, previousFrame.Output[:]...)
|
|
||||||
|
|
||||||
commitmentInput := []byte{}
|
|
||||||
for _, commitment := range commitments {
|
|
||||||
commitmentInput = append(commitmentInput, commitment...)
|
|
||||||
}
|
|
||||||
|
|
||||||
input = append(input, commitmentInput...)
|
|
||||||
|
|
||||||
b := sha3.Sum256(input)
|
|
||||||
v := vdf.New(difficulty, b)
|
|
||||||
|
|
||||||
v.Execute()
|
|
||||||
o := v.GetOutput()
|
|
||||||
|
|
||||||
// TODO: make this configurable for signing algorithms that allow
|
|
||||||
// user-supplied hash functions
|
|
||||||
signature, err := provingKey.Sign(
|
|
||||||
rand.Reader,
|
|
||||||
append(append([]byte{}, b[:]...), o[:]...),
|
|
||||||
crypto.Hash(0),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(
|
|
||||||
err,
|
|
||||||
"prove",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
previousSelectorBytes := [516]byte{}
|
|
||||||
copy(previousSelectorBytes[:], previousFrame.Output[:516])
|
|
||||||
|
|
||||||
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "prove clock frame")
|
|
||||||
}
|
|
||||||
|
|
||||||
frame := &ClockFrame{
|
|
||||||
Filter: previousFrame.Filter,
|
|
||||||
FrameNumber: previousFrame.FrameNumber + 1,
|
|
||||||
Timestamp: timestamp,
|
|
||||||
Difficulty: difficulty,
|
|
||||||
ParentSelector: parent.Bytes(),
|
|
||||||
Input: append(
|
|
||||||
append([]byte{}, previousFrame.Output...),
|
|
||||||
commitmentInput...,
|
|
||||||
),
|
|
||||||
AggregateProofs: aggregateProofs,
|
|
||||||
Output: o[:],
|
|
||||||
}
|
|
||||||
|
|
||||||
switch pubkeyType {
|
|
||||||
case keys.KeyTypeEd448:
|
|
||||||
frame.PublicKeySignature = &ClockFrame_PublicKeySignatureEd448{
|
|
||||||
PublicKeySignatureEd448: &Ed448Signature{
|
|
||||||
Signature: signature,
|
|
||||||
PublicKey: &Ed448PublicKey{
|
|
||||||
KeyValue: pubkey,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, errors.Wrap(
|
|
||||||
errors.New("unsupported proving key"),
|
|
||||||
"prove clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *ClockFrame) VerifyDataClockFrame() error {
|
|
||||||
var pubkey []byte
|
|
||||||
var signature []byte
|
|
||||||
pubkeyType := keys.KeyTypeEd448
|
|
||||||
ed448PublicKey := frame.GetPublicKeySignatureEd448()
|
|
||||||
if ed448PublicKey != nil {
|
|
||||||
pubkey = ed448PublicKey.PublicKey.KeyValue
|
|
||||||
signature = ed448PublicKey.Signature
|
|
||||||
} else {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("no valid signature provided"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
h, err := poseidon.HashBytes(pubkey)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("could not hash proving key"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
address := h.Bytes()
|
|
||||||
|
|
||||||
input := []byte{}
|
|
||||||
input = append(input, frame.Filter...)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, frame.FrameNumber)
|
|
||||||
input = binary.BigEndian.AppendUint64(input, uint64(frame.Timestamp))
|
|
||||||
input = binary.BigEndian.AppendUint32(input, frame.Difficulty)
|
|
||||||
input = append(input, address...)
|
|
||||||
input = append(input, frame.Input...)
|
|
||||||
|
|
||||||
if len(frame.Input) < 516 {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
b := sha3.Sum256(input)
|
|
||||||
v := vdf.New(frame.Difficulty, b)
|
|
||||||
proof := [516]byte{}
|
|
||||||
copy(proof[:], frame.Output)
|
|
||||||
|
|
||||||
// TODO: make this configurable for signing algorithms that allow
|
|
||||||
// user-supplied hash functions
|
|
||||||
switch pubkeyType {
|
|
||||||
case keys.KeyTypeEd448:
|
|
||||||
if len(pubkey) != 57 || len(signature) != 114 || !ed448.VerifyAny(
|
|
||||||
pubkey,
|
|
||||||
append(append([]byte{}, b[:]...), frame.Output...),
|
|
||||||
signature,
|
|
||||||
crypto.Hash(0),
|
|
||||||
) {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid signature for issuer"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !v.Verify(proof) {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("invalid proof"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
previousSelectorBytes := [516]byte{}
|
|
||||||
copy(previousSelectorBytes[:], frame.Input[:516])
|
|
||||||
|
|
||||||
parent, err := poseidon.HashBytes(previousSelectorBytes[:])
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "verify clock frame")
|
|
||||||
}
|
|
||||||
|
|
||||||
selector := new(big.Int).SetBytes(frame.ParentSelector)
|
|
||||||
if parent.Cmp(selector) != 0 {
|
|
||||||
return errors.Wrap(
|
|
||||||
errors.New("selector did not match input"),
|
|
||||||
"verify clock frame",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/reflection"
|
"google.golang.org/grpc/reflection"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application"
|
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/ceremony/application"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
"source.quilibrium.com/quilibrium/monorepo/node/keys"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
|
||||||
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/cockroachdb/pebble"
|
"github.com/cockroachdb/pebble"
|
||||||
"github.com/iden3/go-iden3-crypto/poseidon"
|
"github.com/iden3/go-iden3-crypto/poseidon"
|
||||||
@ -60,6 +58,12 @@ type ClockStore interface {
|
|||||||
frame *protobufs.ClockFrame,
|
frame *protobufs.ClockFrame,
|
||||||
txn Transaction,
|
txn Transaction,
|
||||||
) error
|
) error
|
||||||
|
GetCandidateDataClockFrame(
|
||||||
|
filter []byte,
|
||||||
|
frameNumber uint64,
|
||||||
|
parentSelector []byte,
|
||||||
|
distance []byte,
|
||||||
|
) (*protobufs.ClockFrame, error)
|
||||||
GetCandidateDataClockFrames(
|
GetCandidateDataClockFrames(
|
||||||
filter []byte,
|
filter []byte,
|
||||||
frameNumber uint64,
|
frameNumber uint64,
|
||||||
@ -1055,6 +1059,45 @@ func (p *PebbleClockStore) PutDataClockFrame(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PebbleClockStore) GetCandidateDataClockFrame(
|
||||||
|
filter []byte,
|
||||||
|
frameNumber uint64,
|
||||||
|
parentSelector []byte,
|
||||||
|
distance []byte,
|
||||||
|
) (*protobufs.ClockFrame, error) {
|
||||||
|
value, closer, err := p.db.Get(clockDataCandidateFrameKey(
|
||||||
|
filter,
|
||||||
|
frameNumber,
|
||||||
|
parentSelector,
|
||||||
|
distance,
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, pebble.ErrNotFound) {
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.Wrap(err, "get candidate data clock frame")
|
||||||
|
}
|
||||||
|
|
||||||
|
defer closer.Close()
|
||||||
|
frame := &protobufs.ClockFrame{}
|
||||||
|
if err := proto.Unmarshal(value, frame); err != nil {
|
||||||
|
return nil, errors.Wrap(
|
||||||
|
errors.Wrap(err, ErrInvalidData.Error()),
|
||||||
|
"get candidate data clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.fillAggregateProofs(frame); err != nil {
|
||||||
|
return nil, errors.Wrap(
|
||||||
|
errors.Wrap(err, ErrInvalidData.Error()),
|
||||||
|
"get candidate data clock frame",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetCandidateDataClockFrames implements ClockStore.
|
// GetCandidateDataClockFrames implements ClockStore.
|
||||||
// Distance is 32-byte aligned, so we just use a 0x00 * 32 -> 0xff * 32 range
|
// Distance is 32-byte aligned, so we just use a 0x00 * 32 -> 0xff * 32 range
|
||||||
func (p *PebbleClockStore) GetCandidateDataClockFrames(
|
func (p *PebbleClockStore) GetCandidateDataClockFrames(
|
||||||
@ -1421,162 +1464,6 @@ func (p *PebbleClockStore) GetCompressedDataClockFrames(
|
|||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
return nil, errors.Wrap(err, "get compressed data clock frames")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(syncMessage.TruncatedClockFrames) < int(
|
|
||||||
toFrameNumber-fromFrameNumber+1,
|
|
||||||
) {
|
|
||||||
newFrom := fromFrameNumber
|
|
||||||
if len(syncMessage.TruncatedClockFrames) > 0 {
|
|
||||||
newFrom = syncMessage.TruncatedClockFrames[len(
|
|
||||||
syncMessage.TruncatedClockFrames,
|
|
||||||
)-1].FrameNumber + 1
|
|
||||||
}
|
|
||||||
from := clockDataCandidateFrameKey(
|
|
||||||
filter,
|
|
||||||
newFrom,
|
|
||||||
[]byte{
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
},
|
|
||||||
[]byte{
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
to := clockDataCandidateFrameKey(
|
|
||||||
filter,
|
|
||||||
toFrameNumber+1,
|
|
||||||
[]byte{
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
},
|
|
||||||
[]byte{
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
iter, err := p.db.NewIter(from, to)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
|
|
||||||
candidates := []*protobufs.ClockFrame{}
|
|
||||||
for iter.First(); iter.Valid(); iter.Next() {
|
|
||||||
value := iter.Value()
|
|
||||||
frame := &protobufs.ClockFrame{}
|
|
||||||
if err := proto.Unmarshal(value, frame); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
candidates = append(candidates, frame)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := iter.Close(); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(candidates, func(i, j int) bool {
|
|
||||||
return candidates[i].FrameNumber < candidates[j].FrameNumber
|
|
||||||
})
|
|
||||||
|
|
||||||
if len(candidates) > 0 {
|
|
||||||
cursorStart := candidates[0].FrameNumber
|
|
||||||
paths := [][]*protobufs.ClockFrame{}
|
|
||||||
for _, frame := range candidates {
|
|
||||||
frame := frame
|
|
||||||
if frame.FrameNumber == cursorStart {
|
|
||||||
paths = append(paths, []*protobufs.ClockFrame{frame})
|
|
||||||
}
|
|
||||||
if frame.FrameNumber > cursorStart {
|
|
||||||
for i, path := range paths {
|
|
||||||
s, err := path[len(path)-1].GetSelector()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
parentSelector, _, _, err := frame.GetParentSelectorAndDistance(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
if s.Cmp(parentSelector) == 0 {
|
|
||||||
paths[i] = append(paths[i], frame)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(paths, func(i, j int) bool {
|
|
||||||
return len(paths[i]) > len(paths[j])
|
|
||||||
})
|
|
||||||
|
|
||||||
leadingIndex := 0
|
|
||||||
var leadingScore *big.Int
|
|
||||||
length := len(paths[0])
|
|
||||||
for i := 0; i < len(paths); i++ {
|
|
||||||
if len(paths[i]) < length {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
score := new(big.Int)
|
|
||||||
for _, path := range paths[i] {
|
|
||||||
master, err := p.GetMasterClockFrame(
|
|
||||||
[]byte{
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
},
|
|
||||||
path.FrameNumber,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
|
|
||||||
discriminator, err := master.GetSelector()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, distance, _, err := path.GetParentSelectorAndDistance(
|
|
||||||
discriminator,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get compressed data clock frames")
|
|
||||||
}
|
|
||||||
score = score.Add(score, distance)
|
|
||||||
}
|
|
||||||
if leadingScore == nil || leadingScore.Cmp(score) > 0 {
|
|
||||||
leadingIndex = i
|
|
||||||
leadingScore = score
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, frame := range paths[leadingIndex] {
|
|
||||||
frame := frame
|
|
||||||
syncMessage.TruncatedClockFrames = append(
|
|
||||||
syncMessage.TruncatedClockFrames,
|
|
||||||
frame,
|
|
||||||
)
|
|
||||||
if frame.FrameNumber == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(frame.Input[516:])/74; i++ {
|
|
||||||
aggregateCommit := frame.Input[516+(i*74) : 516+((i+1)*74)]
|
|
||||||
|
|
||||||
if _, ok := proofs[string(aggregateCommit)]; !ok {
|
|
||||||
proofs[string(aggregateCommit)] = &protobufs.InclusionProofsMap{
|
|
||||||
FrameCommit: aggregateCommit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range proofs {
|
for k, v := range proofs {
|
||||||
k := k
|
k := k
|
||||||
v := v
|
v := v
|
||||||
|
Loading…
Reference in New Issue
Block a user