From 6c0e338a300e01372527f51aea9cc37dbf9846fb Mon Sep 17 00:00:00 2001 From: sc0vu Date: Fri, 17 Mar 2023 19:21:08 +0800 Subject: [PATCH 01/25] katzenmint: prune documents if it's not corrected --- katzenmint/state.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/katzenmint/state.go b/katzenmint/state.go index 765908a..f5f2665 100644 --- a/katzenmint/state.go +++ b/katzenmint/state.go @@ -31,6 +31,7 @@ var ( errStateClosed = errors.New("katzenmint state is closed") errDocInsufficientDescriptor = errors.New("insufficient descriptors uploaded") errDocInsufficientProvider = errors.New("no providers uploaded") + errEscapedDocument = errors.New("escaped document") ) type descriptor struct { @@ -145,8 +146,8 @@ func (state *KatzenmintState) Commit() ([]byte, error) { } state.currentEpoch++ state.epochStartHeight = state.blockHeight + 1 - // TODO: Prune related descriptors } + state.pruneDocument() } // Save epoch info persistently @@ -383,6 +384,18 @@ func (state *KatzenmintState) GetDocument(epoch uint64, height int64) ([]byte, * * Document * *****************************************/ +func (s *KatzenmintState) pruneDocument() { + begin := storageKey(descriptorsBucket, []byte{}, s.currentEpoch) + end := storageKey(descriptorsBucket, []byte{}, s.currentEpoch+1) + _ = s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { + _, err := s11n.ParseDescriptorWithoutVerify(value) + if err != nil { + s.tree.Remove(key) + } + return false + }) +} + func (s *KatzenmintState) generateDocument() (*document, error) { // Cannot lock here @@ -390,8 +403,12 @@ func (s *KatzenmintState) generateDocument() (*document, error) { var providersDesc, nodesDesc []*descriptor begin := storageKey(descriptorsBucket, []byte{}, s.currentEpoch) end := storageKey(descriptorsBucket, []byte{}, s.currentEpoch+1) - _ = s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { - desc, _ := s11n.ParseDescriptorWithoutVerify(value) + escaped := s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { + desc, err := s11n.ParseDescriptorWithoutVerify(value) + if err != nil { + // TODO: check different error + return true + } v := &descriptor{desc: desc, raw: value} if v.desc.Layer == pki.LayerProvider { providersDesc = append(providersDesc, v) @@ -401,6 +418,10 @@ func (s *KatzenmintState) generateDocument() (*document, error) { return false }) + if escaped { + return nil, errEscapedDocument + } + // Assign nodes to layers. # No randomness yet. var topology [][][]byte if len(nodesDesc) < s.layers*s.minNodesPerLayer { From 642d4d6b5dca0eca72a32c8bf6e01faa9527e03c Mon Sep 17 00:00:00 2001 From: sc0vu Date: Sat, 18 Mar 2023 16:43:58 +0800 Subject: [PATCH 02/25] katzenmint: remove incorrect descriptors when generate document --- katzenmint/state.go | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/katzenmint/state.go b/katzenmint/state.go index f5f2665..9a16384 100644 --- a/katzenmint/state.go +++ b/katzenmint/state.go @@ -31,7 +31,6 @@ var ( errStateClosed = errors.New("katzenmint state is closed") errDocInsufficientDescriptor = errors.New("insufficient descriptors uploaded") errDocInsufficientProvider = errors.New("no providers uploaded") - errEscapedDocument = errors.New("escaped document") ) type descriptor struct { @@ -147,7 +146,7 @@ func (state *KatzenmintState) Commit() ([]byte, error) { state.currentEpoch++ state.epochStartHeight = state.blockHeight + 1 } - state.pruneDocument() + // TODO: state.pruneDocument() } // Save epoch info persistently @@ -384,18 +383,6 @@ func (state *KatzenmintState) GetDocument(epoch uint64, height int64) ([]byte, * * Document * *****************************************/ -func (s *KatzenmintState) pruneDocument() { - begin := storageKey(descriptorsBucket, []byte{}, s.currentEpoch) - end := storageKey(descriptorsBucket, []byte{}, s.currentEpoch+1) - _ = s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { - _, err := s11n.ParseDescriptorWithoutVerify(value) - if err != nil { - s.tree.Remove(key) - } - return false - }) -} - func (s *KatzenmintState) generateDocument() (*document, error) { // Cannot lock here @@ -403,10 +390,12 @@ func (s *KatzenmintState) generateDocument() (*document, error) { var providersDesc, nodesDesc []*descriptor begin := storageKey(descriptorsBucket, []byte{}, s.currentEpoch) end := storageKey(descriptorsBucket, []byte{}, s.currentEpoch+1) - escaped := s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { + _ = s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { desc, err := s11n.ParseDescriptorWithoutVerify(value) if err != nil { - // TODO: check different error + // might happened when network stuck or the data was corrupted + // should remove the outdated or corrupted data + s.tree.Remove(key) return true } v := &descriptor{desc: desc, raw: value} @@ -418,10 +407,6 @@ func (s *KatzenmintState) generateDocument() (*document, error) { return false }) - if escaped { - return nil, errEscapedDocument - } - // Assign nodes to layers. # No randomness yet. var topology [][][]byte if len(nodesDesc) < s.layers*s.minNodesPerLayer { From 283ea9902763e48e369204290f0c29928762580f Mon Sep 17 00:00:00 2001 From: sc0vu Date: Thu, 4 May 2023 15:33:30 +0800 Subject: [PATCH 03/25] client: add BroadcastTxError --- client/pkiclient/epochtime/epochtime.go | 2 +- client/pkiclient/katzenmint.go | 35 +++++++++++-------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/client/pkiclient/epochtime/epochtime.go b/client/pkiclient/epochtime/epochtime.go index adce526..326114a 100644 --- a/client/pkiclient/epochtime/epochtime.go +++ b/client/pkiclient/epochtime/epochtime.go @@ -8,7 +8,7 @@ import ( "github.com/hashcloak/Meson/katzenmint" ) -//! The duration of a katzenmint epoch. Should refer to katzenmint PKI. +// ! The duration of a katzenmint epoch. Should refer to katzenmint PKI. var TestPeriod = katzenmint.HeightPeriod * time.Duration(katzenmint.EpochInterval) func Now(client kpki.Client) (epoch uint64, ellapsed, till time.Duration, err error) { diff --git a/client/pkiclient/katzenmint.go b/client/pkiclient/katzenmint.go index 001172d..ddfb135 100644 --- a/client/pkiclient/katzenmint.go +++ b/client/pkiclient/katzenmint.go @@ -29,6 +29,17 @@ var ( protocolVersion = "development" ) +type BroadcastTxError struct { + Resp *ctypes.ResultBroadcastTxCommit +} + +func (e BroadcastTxError) Error() string { + if !e.Resp.CheckTx.IsOK() { + return fmt.Sprintf("send transaction failed at checking tx: %v", e.Resp.CheckTx.Log) + } + return fmt.Sprintf("send transaction failed at delivering tx: %v", e.Resp.DeliverTx.Log) +} + type PKIClientConfig struct { LogBackend *log.Backend ChainID string @@ -170,26 +181,12 @@ func (p *PKIClient) Post(ctx context.Context, epoch uint64, signingKey *eddsa.Pr // Post the abci transaction _, err = p.PostTx(ctx, tx) if err != nil { + if _, ok := err.(BroadcastTxError); ok { + return cpki.ErrInvalidPostEpoch + } return err } return nil - - // TODO: Make sure to subscribe for events - // Parse the post_descriptor_status command. - /* - r, ok := resp.(*commands.PostDescriptorStatus) - if !ok { - return fmt.Errorf("nonvoting/client: Post() unexpected reply: %T", resp) - } - switch r.ErrorCode { - case commands.DescriptorOk: - return nil - case commands.DescriptorConflict: - return cpki.ErrInvalidPostEpoch - default: - return fmt.Errorf("nonvoting/client: Post() rejected by authority: %v", postErrorToString(r.ErrorCode)) - } - */ } // PostTx posts the transaction to the katzenmint node. @@ -201,10 +198,10 @@ func (p *PKIClient) PostTx(ctx context.Context, tx []byte) (*ctypes.ResultBroadc return nil, err } if !resp.CheckTx.IsOK() { - return nil, fmt.Errorf("send transaction failed at checking tx: %v", resp.CheckTx.Log) + return nil, BroadcastTxError{Resp: resp} } if !resp.DeliverTx.IsOK() { - return nil, fmt.Errorf("send transaction failed at delivering tx: %v", resp.DeliverTx.Log) + return nil, BroadcastTxError{Resp: resp} } return resp, nil } From 43ff95e052f2e7bb82f2405ad7b245682c1c5946 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Fri, 5 May 2023 16:50:52 +0800 Subject: [PATCH 04/25] server: publish epoch again if the epoch didn't update --- server/internal/pki/pki.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/server/internal/pki/pki.go b/server/internal/pki/pki.go index 6c0182c..1872ab5 100644 --- a/server/internal/pki/pki.go +++ b/server/internal/pki/pki.go @@ -29,6 +29,7 @@ import ( kpki "github.com/hashcloak/Meson/client/pkiclient" "github.com/hashcloak/Meson/client/pkiclient/epochtime" + "github.com/hashcloak/Meson/katzenmint/s11n" "github.com/hashcloak/Meson/server/internal/constants" "github.com/hashcloak/Meson/server/internal/debug" "github.com/hashcloak/Meson/server/internal/glue" @@ -62,6 +63,7 @@ type pki struct { failedFetches map[uint64]error lastPublishedEpoch uint64 lastWarnedEpoch uint64 + lastPublishedTime time.Time } var ( @@ -351,12 +353,23 @@ func (p *pki) publishDescriptorIfNeeded(pkiCtx context.Context) error { return err } if till < publishGracePeriod { - epoch++ + // check whether the certificate is expired and the network stuck + if p.lastPublishedTime.Unix() > 0 { + now := time.Now() + elapsed := now.Sub(p.lastPublishedTime) + if elapsed > s11n.CertificateExpiration { + p.log.Debugf("Publish epoch again: %d.", epoch) + p.lastPublishedEpoch = 0 + } + } else { + epoch++ + } } doPublishEpoch := uint64(0) switch p.lastPublishedEpoch { case 0: // Initial startup. Regardless of the deadline, publish. + // Or publish if network stuck p.log.Debugf("Initial startup or correcting for time jump.") doPublishEpoch = epoch case epoch: @@ -454,15 +467,18 @@ func (p *pki) publishDescriptorIfNeeded(pkiCtx context.Context) error { case nil: p.log.Debugf("Posted descriptor for epoch: %v", doPublishEpoch) p.lastPublishedEpoch = doPublishEpoch + p.lastPublishedTime = time.Now() case cpki.ErrInvalidPostEpoch: // Treat this class (conflict/late descriptor) as a permanent rejection // and suppress further uploads. p.log.Warningf("Authority rejected upload for epoch: %v (Conflict/Late)", doPublishEpoch) p.lastPublishedEpoch = doPublishEpoch + p.lastPublishedTime = time.Now() default: // XXX: the voting authority implementation does not return any of the above error types... // and the mix will continue to fail to submit the same descriptor repeatedly. p.lastPublishedEpoch = doPublishEpoch + p.lastPublishedTime = time.Now() } return err From 3adc25171848ce24141bd249f6880d405e7ad99b Mon Sep 17 00:00:00 2001 From: sc0vu Date: Fri, 5 May 2023 17:02:38 +0800 Subject: [PATCH 05/25] server: update --- server/internal/pki/pki.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/internal/pki/pki.go b/server/internal/pki/pki.go index 1872ab5..eab372c 100644 --- a/server/internal/pki/pki.go +++ b/server/internal/pki/pki.go @@ -358,6 +358,7 @@ func (p *pki) publishDescriptorIfNeeded(pkiCtx context.Context) error { now := time.Now() elapsed := now.Sub(p.lastPublishedTime) if elapsed > s11n.CertificateExpiration { + // Should we republish epoch + 1? p.log.Debugf("Publish epoch again: %d.", epoch) p.lastPublishedEpoch = 0 } @@ -370,7 +371,7 @@ func (p *pki) publishDescriptorIfNeeded(pkiCtx context.Context) error { case 0: // Initial startup. Regardless of the deadline, publish. // Or publish if network stuck - p.log.Debugf("Initial startup or correcting for time jump.") + p.log.Debugf("Initial startup or correcting for network stuck.") doPublishEpoch = epoch case epoch: // Check the deadline for the next publication time. From 6382f365e113d3da82cfcb640e2b34648231f2e3 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 14 May 2023 17:09:04 +0800 Subject: [PATCH 06/25] core: remove rawdocs & GetConsensus wire command --- client/minclient/connection.go | 37 ++++++++++++----------- server/internal/incoming/incoming_conn.go | 23 -------------- server/internal/pki/pki.go | 27 ++--------------- 3 files changed, 22 insertions(+), 65 deletions(-) diff --git a/client/minclient/connection.go b/client/minclient/connection.go index b703c14..f97f40c 100644 --- a/client/minclient/connection.go +++ b/client/minclient/connection.go @@ -444,24 +444,25 @@ func (c *connection) onWireConn(w *wire.Session) { case <-c.fetchCh: doFetch = true case ctx := <-c.getConsensusCh: - c.log.Debugf("Dequeued GetConsesus for send.") - if consensusCtx != nil { - ctx.doneFn(fmt.Errorf("outstanding GetConsensus already exists: %v", consensusCtx.epoch)) - } else { - consensusCtx = ctx - cmd := &commands.GetConsensus{ - Epoch: ctx.epoch, - } - wireErr = w.SendCommand(cmd) - ctx.doneFn(wireErr) - if wireErr != nil { - c.log.Debugf("Failed to send GetConsensus: %v", wireErr) - return - } - c.log.Debugf("Sent GetConsensus.") - } - - adjFetchDelay() + c.log.Debugf("[Deprecated] Dequeued GetConsesus for send.") + ctx.doneFn(fmt.Errorf("deprecated GetConsensus wire command")) + // if consensusCtx != nil { + // ctx.doneFn(fmt.Errorf("outstanding GetConsensus already exists: %v", consensusCtx.epoch)) + // } else { + // consensusCtx = ctx + // cmd := &commands.GetConsensus{ + // Epoch: ctx.epoch, + // } + // wireErr = w.SendCommand(cmd) + // ctx.doneFn(wireErr) + // if wireErr != nil { + // c.log.Debugf("Failed to send GetConsensus: %v", wireErr) + // return + // } + // c.log.Debugf("Sent GetConsensus.") + // } + + // adjFetchDelay() continue case ctx := <-c.sendCh: c.log.Debugf("Dequeued packet for send.") diff --git a/server/internal/incoming/incoming_conn.go b/server/internal/incoming/incoming_conn.go index ce98723..c968125 100644 --- a/server/internal/incoming/incoming_conn.go +++ b/server/internal/incoming/incoming_conn.go @@ -30,7 +30,6 @@ import ( "github.com/katzenpost/core/constants" "github.com/katzenpost/core/crypto/rand" "github.com/katzenpost/core/monotime" - cpki "github.com/katzenpost/core/pki" "github.com/katzenpost/core/sphinx" "github.com/katzenpost/core/utils" "github.com/katzenpost/core/wire" @@ -309,13 +308,6 @@ func (c *incomingConn) worker() { return } continue - case *commands.GetConsensus: - c.log.Debugf("Received GetConsensus from peer.") - if err := c.onGetConsensus(cmd); err != nil { - c.log.Debugf("Failed to handle GetConsensus: %v", err) - return - } - continue default: // Probably a common command, like SendPacket. } @@ -350,21 +342,6 @@ func (c *incomingConn) onMixCommand(rawCmd commands.Command) bool { return false } -func (c *incomingConn) onGetConsensus(cmd *commands.GetConsensus) error { - respCmd := &commands.Consensus{} - rawDoc, err := c.l.glue.PKI().GetRawConsensus(cmd.Epoch) - switch err { - case nil: - respCmd.ErrorCode = commands.ConsensusOk - respCmd.Payload = rawDoc - case cpki.ErrNoDocument: - respCmd.ErrorCode = commands.ConsensusGone - default: // Covers errNotCached - respCmd.ErrorCode = commands.ConsensusNotFound - } - return c.w.SendCommand(respCmd) -} - func (c *incomingConn) onRetrieveMessage(cmd *commands.RetrieveMessage) error { advance := false switch cmd.Sequence { diff --git a/server/internal/pki/pki.go b/server/internal/pki/pki.go index eab372c..f396ac3 100644 --- a/server/internal/pki/pki.go +++ b/server/internal/pki/pki.go @@ -59,7 +59,6 @@ type pki struct { impl kpki.Client descAddrMap map[cpki.Transport][]string docs map[uint64]*pkicache.Entry - rawDocs map[uint64][]byte failedFetches map[uint64]error lastPublishedEpoch uint64 lastWarnedEpoch uint64 @@ -183,7 +182,7 @@ func (p *pki) worker() { continue } - d, rawDoc, err := p.impl.GetDoc(pkiCtx, epoch) + d, _, err := p.impl.GetDoc(pkiCtx, epoch) if isCanceled() { // Canceled mid-fetch. return @@ -214,7 +213,6 @@ func (p *pki) worker() { } p.Lock() - p.rawDocs[epoch] = rawDoc p.docs[epoch] = ent p.Unlock() didUpdate = true @@ -335,7 +333,6 @@ func (p *pki) pruneDocuments() { if epoch+(constants.NumMixKeys-1) < now { p.log.Debugf("Discarding PKI for epoch: %v", epoch) delete(p.docs, epoch) - delete(p.rawDocs, epoch) } if epoch > now+1 { // This should NEVER happen. @@ -688,26 +685,9 @@ func (p *pki) OutgoingDestinations() map[[sConstants.NodeIDLength]byte]*cpki.Mix return descMap } +// TODO: remove this from interface func (p *pki) GetRawConsensus(epoch uint64) ([]byte, error) { - if ok, err := p.getFailedFetch(epoch); ok { - p.log.Debugf("GetRawConsensus failure: no cached PKI document for epoch %v: %v", epoch, err) - return nil, cpki.ErrNoDocument - } - p.RLock() - defer p.RUnlock() - val, ok := p.rawDocs[epoch] - if !ok { - now, _, _, err := p.Now() - if err != nil { - return nil, err - } - // Return cpki.ErrNoDocument if documents will never exist. - if epoch < now-1 { - return nil, cpki.ErrNoDocument - } - return nil, errNotCached - } - return val, nil + return nil, nil } func (p *pki) Now() (epoch uint64, ellapsed time.Duration, till time.Duration, err error) { @@ -723,7 +703,6 @@ func New(glue glue.Glue) (glue.PKI, error) { glue: glue, log: glue.LogBackend().GetLogger("pki"), docs: make(map[uint64]*pkicache.Entry), - rawDocs: make(map[uint64][]byte), failedFetches: make(map[uint64]error), } From 903cd304a0e369b42b0038cb601acee2177b3a95 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Sun, 14 May 2023 17:33:53 +0800 Subject: [PATCH 07/25] core: remove raw from pki cache --- client/pkiclient/cache.go | 13 +++--- server/internal/pki/pki.go | 85 +++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/client/pkiclient/cache.go b/client/pkiclient/cache.go index 31cd829..912bf8a 100644 --- a/client/pkiclient/cache.go +++ b/client/pkiclient/cache.go @@ -41,7 +41,6 @@ var ( ) type cacheEntry struct { - raw []byte doc *pki.Document } @@ -94,7 +93,7 @@ func (c *Cache) GetEpoch(ctx context.Context) (epoch uint64, ellapsedHeight uint func (c *Cache) GetDoc(ctx context.Context, epoch uint64) (*pki.Document, []byte, error) { // Fast path, cache hit. if d := c.cacheGet(epoch); d != nil { - return d.doc, d.raw, nil + return d.doc, nil, nil } // Exit upon halt @@ -116,7 +115,7 @@ func (c *Cache) GetDoc(ctx context.Context, epoch uint64) (*pki.Document, []byte return nil, nil, r case *cacheEntry: // Worker will handle the LRU. - return r.doc, r.raw, nil + return r.doc, nil, nil default: return nil, nil, fmt.Errorf("BUG: pkiclient: worker returned nonsensical result: %+v", r) } @@ -161,6 +160,7 @@ func (c *Cache) insertLRU(newEntry *cacheEntry) { } func (c *Cache) worker() { + // TODO: maybe implement backoff delay? const retryTime = time.Second / 2 var epoch, height uint64 @@ -181,9 +181,6 @@ func (c *Cache) worker() { } ctx = context.Background() epoch, height, err = c.impl.GetEpoch(context.Background()) - if epoch == c.memEpoch && height < uint64(katzenmint.EpochInterval) { - c.memHeight = height - } if err != nil || epoch == c.memEpoch { c.timer.Reset(retryTime) c.Unlock() @@ -211,14 +208,14 @@ func (c *Cache) worker() { // // TODO: This could allow concurrent fetches at some point, but for // most common client use cases, this shouldn't matter much. - d, raw, err := c.impl.GetDoc(ctx, epoch) + d, _, err := c.impl.GetDoc(ctx, epoch) if err != nil { if op != nil { op.doneCh <- err } continue } - e := &cacheEntry{doc: d, raw: raw} + e := &cacheEntry{doc: d} c.insertLRU(e) if op != nil { op.doneCh <- e diff --git a/server/internal/pki/pki.go b/server/internal/pki/pki.go index f396ac3..0e0d6b5 100644 --- a/server/internal/pki/pki.go +++ b/server/internal/pki/pki.go @@ -171,53 +171,54 @@ func (p *pki) worker() { // Fetch the PKI documents as required. var didUpdate bool - now, _, _, _ := epochtime.Now(p.impl) - for _, epoch := range p.documentsToFetch() { - fetchedPKIDocsTimer = prometheus.NewTimer(fetchedPKIDocsDuration) - // Certain errors in fetching documents are treated as hard - // failures that suppress further attempts to fetch the document - // for the epoch. - if ok, err := p.getFailedFetch(epoch); ok { - p.log.Debugf("Skipping fetch for epoch %v: %v", epoch, err) - continue - } + if now, _, _, err := p.Now(); err == nil { + for _, epoch := range p.documentsToFetch() { + fetchedPKIDocsTimer = prometheus.NewTimer(fetchedPKIDocsDuration) + // Certain errors in fetching documents are treated as hard + // failures that suppress further attempts to fetch the document + // for the epoch. + if ok, err := p.getFailedFetch(epoch); ok { + p.log.Debugf("Skipping fetch for epoch %v: %v", epoch, err) + continue + } - d, _, err := p.impl.GetDoc(pkiCtx, epoch) - if isCanceled() { - // Canceled mid-fetch. - return - } - if err != nil { - if epoch <= now { - p.log.Warningf("Failed to fetch PKI for epoch %v: %v", epoch, err) - failedFetchPKIDocs.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}).Inc() - if err == cpki.ErrNoDocument { - p.setFailedFetch(epoch, err) + d, _, err := p.impl.GetDoc(pkiCtx, epoch) + if isCanceled() { + // Canceled mid-fetch. + return + } + if err != nil { + if epoch <= now { + p.log.Warningf("Failed to fetch PKI for epoch %v: %v", epoch, err) + failedFetchPKIDocs.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}).Inc() + if err == cpki.ErrNoDocument { + p.setFailedFetch(epoch, err) + } } + continue } - continue - } - ent, err := pkicache.New(d, p.glue.IdentityKey().PublicKey(), p.glue.Config().Server.IsProvider) - if err != nil { - p.log.Warningf("Failed to generate PKI cache for epoch %v: %v", epoch, err) - p.setFailedFetch(epoch, err) - failedPKICacheGeneration.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}).Inc() - continue - } - if err = p.validateCacheEntry(ent); err != nil { - p.log.Warningf("Generated PKI cache is invalid: %v", err) - p.setFailedFetch(epoch, err) - invalidPKICache.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}).Inc() - continue - } + ent, err := pkicache.New(d, p.glue.IdentityKey().PublicKey(), p.glue.Config().Server.IsProvider) + if err != nil { + p.log.Warningf("Failed to generate PKI cache for epoch %v: %v", epoch, err) + p.setFailedFetch(epoch, err) + failedPKICacheGeneration.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}).Inc() + continue + } + if err = p.validateCacheEntry(ent); err != nil { + p.log.Warningf("Generated PKI cache is invalid: %v", err) + p.setFailedFetch(epoch, err) + invalidPKICache.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}).Inc() + continue + } - p.Lock() - p.docs[epoch] = ent - p.Unlock() - didUpdate = true - fetchedPKIDocs.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}) - fetchedPKIDocsTimer.ObserveDuration() + p.Lock() + p.docs[epoch] = ent + p.Unlock() + didUpdate = true + fetchedPKIDocs.With(prometheus.Labels{"epoch": fmt.Sprintf("%v", epoch)}) + fetchedPKIDocsTimer.ObserveDuration() + } } p.pruneFailures() From 04af2c0a4240832bc649b0cd973ba163429abca4 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 23 May 2023 15:56:30 +0800 Subject: [PATCH 08/25] katzenmint: add cert.GetUnsafe --- katzenmint/app.go | 2 +- katzenmint/s11n/descriptor.go | 4 ++-- katzenmint/state.go | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/katzenmint/app.go b/katzenmint/app.go index c4a35b0..6111068 100644 --- a/katzenmint/app.go +++ b/katzenmint/app.go @@ -7,9 +7,9 @@ import ( dbm "github.com/cosmos/cosmos-db" costypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/hashcloak/Meson/katzenmint/cert" "github.com/hashcloak/Meson/katzenmint/config" "github.com/hashcloak/Meson/katzenmint/s11n" - "github.com/katzenpost/core/crypto/cert" "github.com/katzenpost/core/pki" abcitypes "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" diff --git a/katzenmint/s11n/descriptor.go b/katzenmint/s11n/descriptor.go index 1a5bfc2..3579677 100644 --- a/katzenmint/s11n/descriptor.go +++ b/katzenmint/s11n/descriptor.go @@ -24,7 +24,7 @@ import ( "strconv" "time" - "github.com/katzenpost/core/crypto/cert" + "github.com/hashcloak/Meson/katzenmint/cert" "github.com/katzenpost/core/epochtime" "github.com/katzenpost/core/pki" "github.com/katzenpost/core/sphinx/constants" @@ -89,7 +89,7 @@ func GetVerifierFromDescriptor(rawDesc []byte) (cert.Verifier, error) { } func ParseDescriptorWithoutVerify(b []byte) (*pki.MixDescriptor, error) { - payload, err := cert.GetCertified(b) + payload, err := cert.GetUnsafe(b) if err != nil { return nil, err } diff --git a/katzenmint/state.go b/katzenmint/state.go index 9a16384..c01df05 100644 --- a/katzenmint/state.go +++ b/katzenmint/state.go @@ -392,10 +392,9 @@ func (s *KatzenmintState) generateDocument() (*document, error) { end := storageKey(descriptorsBucket, []byte{}, s.currentEpoch+1) _ = s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { desc, err := s11n.ParseDescriptorWithoutVerify(value) + // might happened when the data was corrupted if err != nil { - // might happened when network stuck or the data was corrupted - // should remove the outdated or corrupted data - s.tree.Remove(key) + // s.tree.Remove(key) return true } v := &descriptor{desc: desc, raw: value} From 79819fdd34f1b6ec49abdffe207db7ad39700e20 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 23 May 2023 16:07:08 +0800 Subject: [PATCH 09/25] katzenmint: add cert --- katzenmint/cert/cert.go | 424 +++++++++++++++++++++++++++++ katzenmint/cert/ed25519_test.go | 297 ++++++++++++++++++++ katzenmint/cert/ed25519_vectors.go | 162 +++++++++++ 3 files changed, 883 insertions(+) create mode 100644 katzenmint/cert/cert.go create mode 100644 katzenmint/cert/ed25519_test.go create mode 100644 katzenmint/cert/ed25519_vectors.go diff --git a/katzenmint/cert/cert.go b/katzenmint/cert/cert.go new file mode 100644 index 0000000..f35deac --- /dev/null +++ b/katzenmint/cert/cert.go @@ -0,0 +1,424 @@ +// cert.go - Cryptographic certificate library. +// Copyright (C) 2018 David Stainton. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Package cert provides a cryptographic certicate library. +package cert + +import ( + "bytes" + "encoding/binary" + "errors" + "sort" + "time" + + "github.com/fxamacker/cbor/v2" +) + +const ( + // CertVersion is the certificate format version. + CertVersion = 0 +) + +var ( + // ErrImpossibleDecode is an impossible decoding error. + ErrImpossibleDecode = errors.New("impossible to decode") + + // ErrImpossibleEncode is an impossible encoding error. + ErrImpossibleEncode = errors.New("impossible to encode") + + // ErrImpossibleOutOfMemory is an impossible out of memory error. + ErrImpossibleOutOfMemory = errors.New("impossible out of memory failure") + + // ErrBadSignature indicates that the given signature does not sign the certificate. + ErrBadSignature = errors.New("signature does not sign certificate") + + // ErrDuplicateSignature indicates that the given signature is already present in the certificate. + ErrDuplicateSignature = errors.New("signature must not be duplicate") + + // ErrInvalidCertified indicates that the certified field is invalid + ErrInvalidCertified = errors.New("invalid certified field of certificate") + + // ErrKeyTypeMismatch indicates that the given signer's key type is different than the signatures present already. + ErrKeyTypeMismatch = errors.New("certificate key type mismatch") + + // ErrInvalidKeyType indicates that the given signer's key type is different than the signatures present already. + ErrInvalidKeyType = errors.New("invalid certificate key type") + + // ErrVersionMismatch indicates that the given certificate is the wrong format version. + ErrVersionMismatch = errors.New("certificate version mismatch") + + // ErrCertificateExpired indicates that the given certificate has expired. + ErrCertificateExpired = errors.New("certificate expired") + + // ErrIdentitySignatureNotFound indicates that for the given signer identity there was no signature present in the certificate. + ErrIdentitySignatureNotFound = errors.New("failure to find signature associated with the given identity") + + // ErrInvalidThreshold indicated the given threshold cannot be used. + ErrInvalidThreshold = errors.New("threshold must be equal or less than the number of verifiers") + + // ErrThresholdNotMet indicates that there were not enough valid signatures to meet the threshold. + ErrThresholdNotMet = errors.New("threshold failure") +) + +// Verifier is used to verify signatures. +type Verifier interface { + // Verify verifies a signature. + Verify(sig, msg []byte) bool + + // Identity returns the Verifier identity. + Identity() []byte +} + +// Signer signs messages. +type Signer interface { + // Sign signs the message and returns the signature. + Sign(msg []byte) []byte + + // Identity returns the Signer identity. + Identity() []byte + + // KeyType returns the key type string. + KeyType() string +} + +// Signature is a cryptographic signature +// which has an associated signer ID. +type Signature struct { + // Identity is the identity of the signer. + Identity []byte + // Payload is the actual signature value. + Payload []byte +} + +// certificate structure for serializing certificates. +type certificate struct { + // Version is the certificate format version. + Version uint32 + + // Expiration is seconds since Unix epoch. + Expiration int64 + + // KeyType indicates the type of key + // that is certified by this certificate. + KeyType string + + // Certified is the data that is certified by + // this certificate. + Certified []byte + + // Signatures are the signature of the certificate. + Signatures []Signature +} + +func (c *certificate) message() ([]byte, error) { + message := new(bytes.Buffer) + err := binary.Write(message, binary.LittleEndian, c.Version) + if err != nil { + return nil, ErrImpossibleOutOfMemory + } + err = binary.Write(message, binary.LittleEndian, c.Expiration) + if err != nil { + return nil, ErrImpossibleOutOfMemory + } + _, err = message.Write([]byte(c.KeyType)) + if err != nil { + return nil, ErrImpossibleOutOfMemory + } + _, err = message.Write(c.Certified) + if err != nil { + return nil, ErrImpossibleOutOfMemory + } + return message.Bytes(), nil +} + +func (c *certificate) basicCheck() error { + if c.Version != CertVersion { + return ErrVersionMismatch + } + if len(c.KeyType) == 0 { + return ErrInvalidKeyType + } + if len(c.Certified) == 0 || c.Certified == nil { + return ErrInvalidCertified + } + return nil +} + +func (c *certificate) sanityCheck() error { + if time.Unix(c.Expiration, 0).Before(time.Now()) { + return ErrCertificateExpired + } + return c.basicCheck() +} + +// Sign uses the given Signer to create a certificate which +// certifies the given data. +func Sign(signer Signer, data []byte, expiration int64) ([]byte, error) { + cert := certificate{ + Version: CertVersion, + Expiration: expiration, + KeyType: signer.KeyType(), + Certified: data, + } + err := cert.sanityCheck() + if err != nil { + return nil, err + } + mesg, err := cert.message() + if err != nil { + return nil, err + } + cert.Signatures = []Signature{ + Signature{ + Identity: signer.Identity(), + Payload: signer.Sign(mesg), + }, + } + return cbor.Marshal(cert) +} + +// GetUnsafe returns the certified data without verified certificate expiration. +func GetUnsafe(rawCert []byte) ([]byte, error) { + cert := certificate{} + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleEncode + } + err = cert.basicCheck() + if err != nil { + return nil, err + } + return cert.Certified, nil +} + +// GetCertified returns the certified data. +func GetCertified(rawCert []byte) ([]byte, error) { + cert := certificate{} + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleEncode + } + err = cert.sanityCheck() + if err != nil { + return nil, err + } + return cert.Certified, nil +} + +// GetSignatures returns all the signatures. +func GetSignatures(rawCert []byte) ([]Signature, error) { + cert := certificate{} + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleEncode + } + err = cert.sanityCheck() + if err != nil { + return nil, err + } + return cert.Signatures, nil +} + +// GetSignature returns a signature that signs the certificate +// if it matches with the given identity. +func GetSignature(identity []byte, rawCert []byte) (*Signature, error) { + cert := certificate{} + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleDecode + } + err = cert.sanityCheck() + if err != nil { + return nil, err + } + for _, s := range cert.Signatures { + if bytes.Equal(identity, s.Identity) { + return &s, nil + } + } + return nil, ErrIdentitySignatureNotFound +} + +type byIdentity []Signature + +func (d byIdentity) Len() int { + return len(d) +} + +func (d byIdentity) Swap(i, j int) { + d[i], d[j] = d[j], d[i] +} + +func (d byIdentity) Less(i, j int) bool { + return bytes.Compare(d[i].Identity, d[j].Identity) < 0 +} + +// SignMulti uses the given signer to create a signature +// and appends it to the certificate and returns it. +func SignMulti(signer Signer, rawCert []byte) ([]byte, error) { + // decode certificate + cert := new(certificate) + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleDecode + } + err = cert.sanityCheck() + if err != nil { + return nil, err + } + if signer.KeyType() != cert.KeyType { + return nil, ErrKeyTypeMismatch + } + + // sign the certificate's message contents + mesg, err := cert.message() + if err != nil { + return nil, err + } + signature := Signature{ + Identity: signer.Identity(), + Payload: signer.Sign(mesg), + } + + // dedup + for _, sig := range cert.Signatures { + if bytes.Equal(sig.Identity, signature.Identity) || bytes.Equal(sig.Payload, signature.Payload) { + return nil, ErrDuplicateSignature + } + } + + cert.Signatures = append(cert.Signatures, signature) + sort.Sort(byIdentity(cert.Signatures)) + + // serialize certificate + out, err := cbor.Marshal(&cert) + if err != nil { + return nil, ErrImpossibleEncode + } + return out, nil +} + +// AddSignature adds the signature to the certificate if the verifier +// can verify the signature signs the certificate. +func AddSignature(verifier Verifier, signature Signature, rawCert []byte) ([]byte, error) { + // decode certificate + cert := new(certificate) + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleDecode + } + + err = cert.sanityCheck() + if err != nil { + return nil, err + } + + // dedup + for _, sig := range cert.Signatures { + if bytes.Equal(sig.Identity, signature.Identity) || bytes.Equal(sig.Payload, signature.Payload) { + return nil, ErrDuplicateSignature + } + } + + // sign the certificate's message contents + mesg, err := cert.message() + if err != nil { + return nil, err + } + if verifier.Verify(signature.Payload, mesg) { + cert.Signatures = append(cert.Signatures, signature) + sort.Sort(byIdentity(cert.Signatures)) + } else { + return nil, ErrBadSignature + } + // serialize certificate + out, err := cbor.Marshal(cert) + if err != nil { + return nil, ErrImpossibleEncode + } + return out, nil +} + +// Verify is used to verify one of the signatures attached to the certificate. +// It returns the certified data if the signature is valid. +func Verify(verifier Verifier, rawCert []byte) ([]byte, error) { + cert := new(certificate) + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, err + } + + err = cert.sanityCheck() + if err != nil { + return nil, err + } + + for _, sig := range cert.Signatures { + if bytes.Equal(verifier.Identity(), sig.Identity) { + mesg, err := cert.message() + if err != nil { + return nil, err + } + if verifier.Verify(sig.Payload, mesg) { + return cert.Certified, nil + } + return nil, ErrBadSignature + } + } + return nil, ErrIdentitySignatureNotFound +} + +// VerifyAll returns the certified data if all of the given verifiers +// can verify the certificate. Otherwise nil is returned along with an error. +func VerifyAll(verifiers []Verifier, rawCert []byte) ([]byte, error) { + var err error + certified := []byte{} + for _, verifier := range verifiers { + certified, err = Verify(verifier, rawCert) + if err != nil { + return nil, err + } + } + return certified, nil +} + +// VerifyThreshold returns the certified data, the succeeded verifiers +// and the failed verifiers if at least a threshold number of verifiers +// can verify the certificate. Otherwise nil is returned along with an +// error. +func VerifyThreshold(verifiers []Verifier, threshold int, rawCert []byte) ([]byte, []Verifier, []Verifier, error) { + if threshold > len(verifiers) { + return nil, nil, nil, ErrInvalidThreshold + } + certified := []byte{} + count := 0 + good := []Verifier{} + bad := []Verifier{} + for _, verifier := range verifiers { + c, err := Verify(verifier, rawCert) + if err != nil { + bad = append(bad, verifier) + continue + } + good = append(good, verifier) + certified = c + count++ + } + if count >= threshold { + return certified, good, bad, nil + } + return nil, good, bad, ErrThresholdNotMet +} diff --git a/katzenmint/cert/ed25519_test.go b/katzenmint/cert/ed25519_test.go new file mode 100644 index 0000000..cfe8d39 --- /dev/null +++ b/katzenmint/cert/ed25519_test.go @@ -0,0 +1,297 @@ +// ed25519_test.go - ed25519 certificate tests. +// Copyright (C) 2018 David Stainton. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cert + +import ( + "bytes" + "testing" + "time" + + "github.com/katzenpost/core/crypto/eddsa" + "github.com/katzenpost/core/crypto/rand" + "github.com/stretchr/testify/assert" +) + +func TestEd25519ExpiredCertificate(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration six months ago + expiration := time.Now().AddDate(0, -6, 0).Unix() + + certificate, err := Sign(signingPrivKey, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.Error(err) + + certified, err := Verify(ephemeralPrivKey.PublicKey(), certificate) + assert.Error(err) + assert.Nil(certified) +} + +func TestEd25519Certificate(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expires 600 years after unix epoch + expiration := time.Unix(0, 0).AddDate(600, 0, 0).Unix() + + toSign := ephemeralPrivKey.PublicKey().Bytes() + certificate, err := Sign(signingPrivKey, toSign, expiration) + assert.NoError(err) + + mesg, err := Verify(signingPrivKey.PublicKey(), certificate) + assert.NoError(err) + assert.NotNil(mesg) + assert.Equal(mesg, toSign) +} + +func TestEd25519BadCertificate(t *testing.T) { + assert := assert.New(t) + + signingPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + certified := signingPrivKey.PublicKey().Bytes() + certified[3] = 235 // modify the signed data so that the Verify will fail + + certificate, err := Sign(signingPrivKey, certified, expiration) + assert.NoError(err) + + mesg, err := Verify(signingPrivKey.PublicKey(), certificate) + assert.Error(err) + assert.Equal(ErrBadSignature, err) + assert.Nil(mesg) +} + +func TestEd25519WrongCertificate(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + certificate, err := Sign(signingPrivKey, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + + mesg, err := Verify(ephemeralPrivKey.PublicKey(), certificate) + assert.Error(err) + assert.Nil(mesg) +} + +func TestEd25519MultiSignatureCertificate(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey1, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey2, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + + certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + + certificate, err = SignMulti(signingPrivKey2, certificate) + assert.NoError(err) + + certificate, err = SignMulti(signingPrivKey3, certificate) + assert.NoError(err) + + mesg, err := Verify(signingPrivKey1.PublicKey(), certificate) + assert.NoError(err) + assert.NotNil(mesg) + + mesg, err = Verify(signingPrivKey2.PublicKey(), certificate) + assert.NoError(err) + assert.NotNil(mesg) + + mesg, err = Verify(signingPrivKey3.PublicKey(), certificate) + assert.NoError(err) + assert.NotNil(mesg) +} + +func TestEd25519MultiSignatureOrdering(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey1, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey2, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + + // 1 + certificate1, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + certificate1, err = SignMulti(signingPrivKey2, certificate1) + assert.NoError(err) + certificate1, err = SignMulti(signingPrivKey3, certificate1) + assert.NoError(err) + + // 2 + certificate2, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + certificate2, err = SignMulti(signingPrivKey3, certificate2) + assert.NoError(err) + certificate2, err = SignMulti(signingPrivKey2, certificate2) + assert.NoError(err) + + assert.Equal(certificate1, certificate2) + + // 3 + certificate3, err := Sign(signingPrivKey2, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + certificate3, err = SignMulti(signingPrivKey3, certificate3) + assert.NoError(err) + certificate3, err = SignMulti(signingPrivKey1, certificate3) + assert.NoError(err) + + assert.Equal(certificate3, certificate2) +} + +func TestEd25519VerifyAll(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey1, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey2, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + + certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + + certificate, err = SignMulti(signingPrivKey2, certificate) + assert.NoError(err) + + certificate, err = SignMulti(signingPrivKey3, certificate) + assert.NoError(err) + + verifiers := []Verifier{signingPrivKey1.PublicKey(), signingPrivKey2.PublicKey(), signingPrivKey2.PublicKey()} + mesg, err := VerifyAll(verifiers, certificate) + assert.NoError(err) + assert.NotNil(mesg) +} + +func TestEd25519VerifyThreshold(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey1, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey2, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey4, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + + certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + + certificate, err = SignMulti(signingPrivKey2, certificate) + assert.NoError(err) + + certificate, err = SignMulti(signingPrivKey3, certificate) + assert.NoError(err) + + verifiers := []Verifier{signingPrivKey1.PublicKey(), signingPrivKey2.PublicKey(), signingPrivKey4.PublicKey()} + threshold := 2 + mesg, good, bad, err := VerifyThreshold(verifiers, threshold, certificate) + assert.NoError(err) + assert.NotNil(mesg) + assert.Equal(bad[0].Identity(), signingPrivKey4.Identity()) + hasVerifier := func(verifier Verifier) bool { + for _, v := range good { + if bytes.Equal(v.Identity(), verifier.Identity()) { + return true + } + } + return false + } + assert.True(hasVerifier(signingPrivKey1.PublicKey())) + assert.True(hasVerifier(signingPrivKey2.PublicKey())) + assert.False(hasVerifier(signingPrivKey4.PublicKey())) +} + +func TestEd25519AddSignature(t *testing.T) { + assert := assert.New(t) + + ephemeralPrivKey, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + signingPrivKey1, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + signingPrivKey2, err := eddsa.NewKeypair(rand.Reader) + assert.NoError(err) + + // expiration in six months + expiration := time.Now().AddDate(0, 6, 0).Unix() + + certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) + assert.NoError(err) + + certificate2, err := SignMulti(signingPrivKey2, certificate) + assert.NoError(err) + + sig, err := GetSignature(signingPrivKey2.Identity(), certificate2) + assert.NoError(err) + assert.NotNil(sig) + certificate3, err := AddSignature(signingPrivKey2.PublicKey(), *sig, certificate) + assert.NoError(err) + + assert.Equal(certificate2, certificate3) +} diff --git a/katzenmint/cert/ed25519_vectors.go b/katzenmint/cert/ed25519_vectors.go new file mode 100644 index 0000000..c272d65 --- /dev/null +++ b/katzenmint/cert/ed25519_vectors.go @@ -0,0 +1,162 @@ +// ed25519_vectors_test.go - ed25519 certificate test vectors. +// Copyright (C) 2018 David Stainton. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cert + +import ( + "encoding/hex" + "testing" + "time" + + "github.com/katzenpost/core/crypto/eddsa" + "github.com/stretchr/testify/assert" +) + +type inTest struct { + signingKey string + toSign string +} + +type outTest struct { + payload string +} + +func TestEd25519SingleSignatureCertificateVectors(t *testing.T) { + assert := assert.New(t) + + certificateTests := []struct { + in inTest + want outTest + }{ + { + inTest{ + signingKey: "e818ee275ddb72b8e63758dfba3a90e0f5687dd59f28c2812e9861ba19fa33bffb731cf47b3732b24a5f9c00a0304b66d461b23e7292c5eb406ec09adc2d95e0", + toSign: "32d4f52620a57aa2b02564c296c0b4b0dbeca5471704a9f40000706bcc134d2f", + }, outTest{ + payload: "a56756657273696f6e006a45787069726174696f6e1b0000000468912f00674b657954797065676564323535313969436572746966696564582032d4f52620a57aa2b02564c296c0b4b0dbeca5471704a9f40000706bcc134d2f6a5369676e61747572657381a2684964656e746974795820fb731cf47b3732b24a5f9c00a0304b66d461b23e7292c5eb406ec09adc2d95e0675061796c6f6164584021fc981035cdd87fb480e5538d321276034c422c0adaf1413fe89a9c3ad99d5fdc18b8d7756ccc920ba4ad63a63ca4de5ffc3ab2ae9fcf028c01a56c025dcc06", + }, + }, + { + inTest{ + signingKey: "f99bdb809088a609c270f612a0e44844d03d86a63e109966ca66f6678cc02a1065efbc72434d921af5285c0fd28af6ed8592c0ac44c834d9d98f5589ea21c03f", + toSign: "ea7b8ef81c91986d93f0532c1de06ce25373c20782d8106ac6a4d85eee4802bb", + }, outTest{ + payload: "a56756657273696f6e006a45787069726174696f6e1b0000000468912f00674b6579547970656765643235353139694365727469666965645820ea7b8ef81c91986d93f0532c1de06ce25373c20782d8106ac6a4d85eee4802bb6a5369676e61747572657381a2684964656e74697479582065efbc72434d921af5285c0fd28af6ed8592c0ac44c834d9d98f5589ea21c03f675061796c6f6164584027fffa55f9b2b8a0de9a7c7c3ceae28c5eeef46239ccac0ef840b425d5ee19ed826c152289294d5f63cd5090c53303bee9561fa98a1e74cc3c4cdd8cc6729606", + }, + }, + { + inTest{ + signingKey: "13a40a6146651427a769e3dd17dc86d4497f5379aa077488fc8d40ce062675bf39b956e6aae2b76a13dd83c0eb96c3e2b22e6ad4e944625a7c0230b4561b82d9", + toSign: "220b7f2efa95f089a75711aad6c843d9899af3e622f7adf06da6d7264ed0ece5093f423dc1fb5d1672643fa133680e49ce74ad5c0367ba0aee902b41a2ad3e9ffbb8db5503b33f0ae61ca28a01bf1b8615d8c2c5f9ac02572e89c76aef5c8b00c052ba4b13ef043fc9f39b90eed1e2e9bccc06a67d3cde025e0b7cfc15cc3efacc50b7bbc525e02f5c52f920b9e03bef07b320f37347359888feaed0ab4d83e0cc6877f00162b3ac424df7cee0b47f1a9f00d49651c2982e59504c889182cda7130e7f83949e193f", + }, outTest{ + payload: "a56756657273696f6e006a45787069726174696f6e1b0000000468912f00674b65795479706567656432353531396943657274696669656458c8220b7f2efa95f089a75711aad6c843d9899af3e622f7adf06da6d7264ed0ece5093f423dc1fb5d1672643fa133680e49ce74ad5c0367ba0aee902b41a2ad3e9ffbb8db5503b33f0ae61ca28a01bf1b8615d8c2c5f9ac02572e89c76aef5c8b00c052ba4b13ef043fc9f39b90eed1e2e9bccc06a67d3cde025e0b7cfc15cc3efacc50b7bbc525e02f5c52f920b9e03bef07b320f37347359888feaed0ab4d83e0cc6877f00162b3ac424df7cee0b47f1a9f00d49651c2982e59504c889182cda7130e7f83949e193f6a5369676e61747572657381a2684964656e74697479582039b956e6aae2b76a13dd83c0eb96c3e2b22e6ad4e944625a7c0230b4561b82d9675061796c6f6164584004dcfeb5499b1c429209c815b49c78ca699f7e869c8cf0f8dff3e6475dd830a33afd72d1dc2d10f1eb198ba5e1e9f9d8efaead9c9f57b929ba3b6d1ee48f8102", + }, + }, + } + + for _, test := range certificateTests { + // expires 600 years after unix epoch + expiration := time.Unix(18934214400, 0).Unix() + signingKeyRaw, err := hex.DecodeString(test.in.signingKey) + assert.NoError(err) + toSign, err := hex.DecodeString(test.in.toSign) + assert.NoError(err) + signingKey := new(eddsa.PrivateKey) + signingKey.FromBytes(signingKeyRaw) + certificate, err := Sign(signingKey, toSign, expiration) + assert.NoError(err) + payload, err := hex.DecodeString(test.want.payload) + assert.NoError(err) + assert.Equal(certificate, payload) + } +} + +type multiSigTest struct { + signingKeys []string + toSign string +} + +func TestEd25519MultipleSignatureCertificateVectors(t *testing.T) { + assert := assert.New(t) + + certificateTests := []struct { + in multiSigTest + want outTest + }{ + { + multiSigTest{ + signingKeys: []string{ + "e818ee275ddb72b8e63758dfba3a90e0f5687dd59f28c2812e9861ba19fa33bffb731cf47b3732b24a5f9c00a0304b66d461b23e7292c5eb406ec09adc2d95e0", + "f99bdb809088a609c270f612a0e44844d03d86a63e109966ca66f6678cc02a1065efbc72434d921af5285c0fd28af6ed8592c0ac44c834d9d98f5589ea21c03f", + }, + toSign: "32d4f52620a57aa2b02564c296c0b4b0dbeca5471704a9f40000706bcc134d2f", + }, outTest{ + payload: "a56756657273696f6e006a45787069726174696f6e1b0000000468912f00674b657954797065676564323535313969436572746966696564582032d4f52620a57aa2b02564c296c0b4b0dbeca5471704a9f40000706bcc134d2f6a5369676e61747572657382a2684964656e74697479582065efbc72434d921af5285c0fd28af6ed8592c0ac44c834d9d98f5589ea21c03f675061796c6f6164584059c6efc14d49f28b804b6fa3cb28e9066cb5b2ea5ddea3173284cf3cde7626e194022466258fc0c84f1006b05698d5932b24c4c50e91da91017ee48669c44c0fa2684964656e746974795820fb731cf47b3732b24a5f9c00a0304b66d461b23e7292c5eb406ec09adc2d95e0675061796c6f6164584021fc981035cdd87fb480e5538d321276034c422c0adaf1413fe89a9c3ad99d5fdc18b8d7756ccc920ba4ad63a63ca4de5ffc3ab2ae9fcf028c01a56c025dcc06", + }, + }, + { + multiSigTest{ + signingKeys: []string{ + "e818ee275ddb72b8e63758dfba3a90e0f5687dd59f28c2812e9861ba19fa33bffb731cf47b3732b24a5f9c00a0304b66d461b23e7292c5eb406ec09adc2d95e0", + "f99bdb809088a609c270f612a0e44844d03d86a63e109966ca66f6678cc02a1065efbc72434d921af5285c0fd28af6ed8592c0ac44c834d9d98f5589ea21c03f", + "13a40a6146651427a769e3dd17dc86d4497f5379aa077488fc8d40ce062675bf39b956e6aae2b76a13dd83c0eb96c3e2b22e6ad4e944625a7c0230b4561b82d9", + }, + toSign: "32d4f52620a57aa2b02564c296c0b4b0dbeca5471704a9f40000706bcc134d2f", + }, outTest{ + payload: "a56756657273696f6e006a45787069726174696f6e1b0000000468912f00674b657954797065676564323535313969436572746966696564582032d4f52620a57aa2b02564c296c0b4b0dbeca5471704a9f40000706bcc134d2f6a5369676e61747572657383a2684964656e74697479582039b956e6aae2b76a13dd83c0eb96c3e2b22e6ad4e944625a7c0230b4561b82d9675061796c6f61645840aabca1e5d737f49f37e3576d66eb7bf40e371cb411151a33fce57bad56aa8c7434d236eee23f2eb245a0d727ea1c4abd8a6a259ce01540a79af112e8ade10c04a2684964656e74697479582065efbc72434d921af5285c0fd28af6ed8592c0ac44c834d9d98f5589ea21c03f675061796c6f6164584059c6efc14d49f28b804b6fa3cb28e9066cb5b2ea5ddea3173284cf3cde7626e194022466258fc0c84f1006b05698d5932b24c4c50e91da91017ee48669c44c0fa2684964656e746974795820fb731cf47b3732b24a5f9c00a0304b66d461b23e7292c5eb406ec09adc2d95e0675061796c6f6164584021fc981035cdd87fb480e5538d321276034c422c0adaf1413fe89a9c3ad99d5fdc18b8d7756ccc920ba4ad63a63ca4de5ffc3ab2ae9fcf028c01a56c025dcc06", + }, + }, + { + multiSigTest{ + signingKeys: []string{ + "b82b2fbb1fa8fbf771dc85dc45e66a1626d44cf3361f3a61e387b266445346dec57a0f83107b9ded621900615ca8ad5fda6f7bc839fb0fbf6f4b6af59611c710", + "4b888f00728a6b7594f8eb6440e4a084889017d2d520ac7b3a8d0b5030872329d12f2a5061f93b378b94f72ddb2082e3e18681d902d4c65ae95c41001e8821be", + "e5ac1b84e158d06ace83947a5fba08af9b000d195503dae4d4a9728b5c0cef9ae896881e859d836443a4c6dfb7fbd3cd07160065b8eb000a4297c7c5c194e287", + "e66cc68c6606f1072485164e6ff989abaf1cef493ba25e922bbcb601769dc4dca3bfdb632fdc227a276e17b2b573d31c7e6bbb236c25af5c5ffde17139d9e4bd", + }, + toSign: "2f15f386b80725ad11e1b2b55b53eeaea003a6cc6e5c359f344fb7af6f39dc043140578009262ea3247aef5e84c0a79e5962506185b54601b93d6d53bdc64dbcb27543657d2229096276a0e677f61cff7cb7c04bfc453b377bc780acb3163346cf3bcaffd0355ca29a6e47a981d85631b6c7c4bef767502d6982dc176df9776b217c2fe62886b139e48ea658c9aa450d995cc6d1bae5a220187694d120fa43fc77be3b3e57ea1a2d1f4247e6a580b8529063eb5dc44c5d64bab43474c66994bb36d149dfee4660ce5e1b8dc9edf8ca407a21519ecfdda6e7c3c3fd83257dc77e02f9c20cc1d68f56255a8e7147b3b6b334039d520215b5d219e899ebd454f3ba1f502f2b9710cc4cde4ec09d6ece17c19ee101eb42459cd3dfc1d7de76b58d4b0fed25335cb0756ea7eb2e762bc139ab8ec7ac8ea4240e034a95011649c5f856ed49e803f41e846a9043b320690b272d3b236af33e8a7d5fbb08a62edca052a58db32143c7b290a129303633ba944f5b9b66ce0123428bb20e7d8d26fb24bf0f5c2fa72a703d8bd31756ae540d887529832e48d8780efcab4e5c2cb59c89d853905562fd76920fd53f415e9cbdb6417a89de8b6ecf71051e877f2a230cee85b150f1479573b01ee7e486e2240b104df54f1dcfb469b946a6547eab1c32631d4171eb008d829231ce18155391570de540b1872a42c8547550f4b53a27430afa517784f32f849181243fc1ba3781caa4031829d491aa9b094ec6516c96880b013a25e4c94ad127452c0df9bd3ddb7eb108a7bfe65fee0626097c55c9a4ff55ac1a6ba5b85ae13408cb5d3e9a64bfbaa1848112f95ffc409229928ebcedde1ff4379ce69141d95dfc1fb10466d6fdfbeee2cccf961b71f2c59824ad43bf05ca9b0d5e48182f83cc61671354c72dfffb4a755cc44d3bd959078078a84ebfcf5a3817e820809ed87eb8d66adc5da1d55c33d8cb882f39f06590cbb9a52f21", + }, outTest{ + payload: "a56756657273696f6e006a45787069726174696f6e1b0000000468912f00674b6579547970656765643235353139694365727469666965645902bc2f15f386b80725ad11e1b2b55b53eeaea003a6cc6e5c359f344fb7af6f39dc043140578009262ea3247aef5e84c0a79e5962506185b54601b93d6d53bdc64dbcb27543657d2229096276a0e677f61cff7cb7c04bfc453b377bc780acb3163346cf3bcaffd0355ca29a6e47a981d85631b6c7c4bef767502d6982dc176df9776b217c2fe62886b139e48ea658c9aa450d995cc6d1bae5a220187694d120fa43fc77be3b3e57ea1a2d1f4247e6a580b8529063eb5dc44c5d64bab43474c66994bb36d149dfee4660ce5e1b8dc9edf8ca407a21519ecfdda6e7c3c3fd83257dc77e02f9c20cc1d68f56255a8e7147b3b6b334039d520215b5d219e899ebd454f3ba1f502f2b9710cc4cde4ec09d6ece17c19ee101eb42459cd3dfc1d7de76b58d4b0fed25335cb0756ea7eb2e762bc139ab8ec7ac8ea4240e034a95011649c5f856ed49e803f41e846a9043b320690b272d3b236af33e8a7d5fbb08a62edca052a58db32143c7b290a129303633ba944f5b9b66ce0123428bb20e7d8d26fb24bf0f5c2fa72a703d8bd31756ae540d887529832e48d8780efcab4e5c2cb59c89d853905562fd76920fd53f415e9cbdb6417a89de8b6ecf71051e877f2a230cee85b150f1479573b01ee7e486e2240b104df54f1dcfb469b946a6547eab1c32631d4171eb008d829231ce18155391570de540b1872a42c8547550f4b53a27430afa517784f32f849181243fc1ba3781caa4031829d491aa9b094ec6516c96880b013a25e4c94ad127452c0df9bd3ddb7eb108a7bfe65fee0626097c55c9a4ff55ac1a6ba5b85ae13408cb5d3e9a64bfbaa1848112f95ffc409229928ebcedde1ff4379ce69141d95dfc1fb10466d6fdfbeee2cccf961b71f2c59824ad43bf05ca9b0d5e48182f83cc61671354c72dfffb4a755cc44d3bd959078078a84ebfcf5a3817e820809ed87eb8d66adc5da1d55c33d8cb882f39f06590cbb9a52f216a5369676e61747572657384a2684964656e746974795820a3bfdb632fdc227a276e17b2b573d31c7e6bbb236c25af5c5ffde17139d9e4bd675061796c6f61645840d47ca94d60175981d66f917f1f4bbe8fa42a13980bcf5a6d5259c010ce326ed12849c97386ec2971f5fc291f0b79b2a88b77e7d8190e4cd00b0a2121f866580ca2684964656e746974795820c57a0f83107b9ded621900615ca8ad5fda6f7bc839fb0fbf6f4b6af59611c710675061796c6f616458407256455cc9378b2e2fc5ba04840b39c493fb2a5eb58ac9dfe85b5c55f595497107fc57bef798fccdce69e699d288111d60a9e35521e852b3c3daf824b1dbb308a2684964656e746974795820d12f2a5061f93b378b94f72ddb2082e3e18681d902d4c65ae95c41001e8821be675061796c6f616458402982e2b91b14f7a5e9f6fe91474c6605eb827403bd2074463c0fb52aa0cbf3b2fd8dbc9d863a3c3bd56298152f1803292410fbdabac8713ee32777024637c609a2684964656e746974795820e896881e859d836443a4c6dfb7fbd3cd07160065b8eb000a4297c7c5c194e287675061796c6f616458409d9f1f59a1a0c9ae10bca5586aea5da615405abc7efa2c20498564bc7051399344e8e466b69f60292babe51fea6b43fb920c0c18d3535b8f64c587efc39f3307", + }, + }, + } + + for _, test := range certificateTests { + // expires 600 years after unix epoch + expiration := time.Unix(18934214400, 0).Unix() + + sigKeys := []*eddsa.PrivateKey{} + for _, key := range test.in.signingKeys { + signingKeyRaw, err := hex.DecodeString(key) + assert.NoError(err) + signingKey := new(eddsa.PrivateKey) + signingKey.FromBytes(signingKeyRaw) + sigKeys = append(sigKeys, signingKey) + } + + toSign, err := hex.DecodeString(test.in.toSign) + assert.NoError(err) + certificate, err := Sign(sigKeys[0], toSign, expiration) + assert.NoError(err) + for _, signingKey := range sigKeys[1:] { + certificate, err = SignMulti(signingKey, certificate) + assert.NoError(err) + } + payload, err := hex.DecodeString(test.want.payload) + assert.NoError(err) + assert.Equal(certificate, payload) + } +} From 06ca2eb501e8e9c1176f282f04f24fea526fa178 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Wed, 12 Jul 2023 16:04:05 +0800 Subject: [PATCH 10/25] server: add cpu profile and memory profile --- server/cmd/meson-server/main.go | 29 +++++++++++++++++++++++++++++ testnet/local/cleanup.sh | 6 ++++++ 2 files changed, 35 insertions(+) diff --git a/server/cmd/meson-server/main.go b/server/cmd/meson-server/main.go index 0c44554..c621275 100644 --- a/server/cmd/meson-server/main.go +++ b/server/cmd/meson-server/main.go @@ -22,6 +22,7 @@ import ( "os" "os/signal" "runtime" + "runtime/pprof" "syscall" server "github.com/hashcloak/Meson/server" @@ -32,8 +33,36 @@ func main() { cfgFile := flag.String("f", "katzenpost.toml", "Path to the server config file.") genOnly := flag.Bool("g", false, "Generate the keys and exit immediately.") testConfig := flag.Bool("t", false, "Test meson server config.") + cpuProfilePath := flag.String("cpuprofilepath", "", "Path to the pprof cpu profile") + memProfilePath := flag.String("memprofilepath", "", "Path to the pprof memory profile") flag.Parse() + if *cpuProfilePath != "" { + f, err := os.Create(*cpuProfilePath) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to create CPU profile '%v': %v\n", *cpuProfilePath, err) + os.Exit(1) + } + if err := pprof.StartCPUProfile(f); err != nil { + fmt.Fprintf(os.Stderr, "Failed to start CPU profile '%v': %v\n", *cpuProfilePath, err) + os.Exit(1) + } + defer pprof.StopCPUProfile() + } + + if *memProfilePath != "" { + f, err := os.Create(*memProfilePath) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to create memory profile '%v': %v\n", *memProfilePath, err) + os.Exit(1) + } + if err := pprof.WriteHeapProfile(f); err != nil { + fmt.Fprintf(os.Stderr, "Failed to write memory profile'%v': %v\n", *memProfilePath, err) + os.Exit(1) + } + f.Close() + } + // Set the umask to something "paranoid". syscall.Umask(0077) diff --git a/testnet/local/cleanup.sh b/testnet/local/cleanup.sh index 139efbc..36c6870 100644 --- a/testnet/local/cleanup.sh +++ b/testnet/local/cleanup.sh @@ -22,6 +22,12 @@ clean_provider_dir () { if [ -d $d/data ]; then rm -rf $d/data/* fi; + if [ -f $d/cpu.prof ]; then + rm -rf $d/cpu.prof + fi; + if [ -f $d/mem.prof ]; then + rm -rf $d/mem.prof + fi; fi; } From 984f8cc9c9f0077c11802b536a5066b16d34fefe Mon Sep 17 00:00:00 2001 From: sc0vu Date: Wed, 12 Jul 2023 16:15:55 +0800 Subject: [PATCH 11/25] katzenmint: add cpu profile and memory profile --- katzenmint/cmd/katzenmint/run.go | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/katzenmint/cmd/katzenmint/run.go b/katzenmint/cmd/katzenmint/run.go index f43f56f..24fd4a3 100644 --- a/katzenmint/cmd/katzenmint/run.go +++ b/katzenmint/cmd/katzenmint/run.go @@ -5,6 +5,7 @@ import ( "os" "os/signal" "path/filepath" + "runtime/pprof" "strings" "syscall" @@ -32,8 +33,10 @@ var ( Short: "Run katzenmint PKI node", RunE: runNode, } - configFile string - dbCacheSize int + configFile string + dbCacheSize int + cpuProfilePath string + memProfilePath string ) func readTendermintConfig(tConfigFile string) (config *cfg.Config, err error) { @@ -107,6 +110,8 @@ func newTendermint(app abci.Application, config *cfg.Config, logger log.Logger) func init() { rootCmd.PersistentFlags().StringVar(&configFile, "config", "katzenmint.toml", "Path to katzenmint.toml") runCmd.Flags().IntVar(&dbCacheSize, "dbcachesize", 100, "Cache size for katzenmint db") + runCmd.Flags().StringVar(&cpuProfilePath, "cpuprofilepath", "", "Path to the pprof cpu profile") + runCmd.Flags().StringVar(&memProfilePath, "memprofilepath", "", "Path to the pprof memory profile") rootCmd.AddCommand(runCmd) rootCmd.AddCommand(registerValidatorCmd) rootCmd.AddCommand(showNodeIDCmd) @@ -126,6 +131,27 @@ func runNode(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("failed to load config: %v", err) } + if cpuProfilePath != "" { + f, err := os.Create(cpuProfilePath) + if err != nil { + return fmt.Errorf("failed to create CPU profile '%v': %v\n", cpuProfilePath, err) + } + if err := pprof.StartCPUProfile(f); err != nil { + return fmt.Errorf("failed to start CPU profile '%v': %v\n", cpuProfilePath, err) + } + defer pprof.StopCPUProfile() + } + + if memProfilePath != "" { + f, err := os.Create(memProfilePath) + if err != nil { + return fmt.Errorf("failed to create memory profile '%v': %v\n", memProfilePath, err) + } + if err := pprof.WriteHeapProfile(f); err != nil { + return fmt.Errorf("failed to write memory profile'%v': %v\n", memProfilePath, err) + } + f.Close() + } db, err := dbm.NewDB("katzenmint_db", dbm.GoLevelDBBackend, kConfig.DBPath) if err != nil { return fmt.Errorf("failed to open badger db: %v\ntry running with -tags badgerdb", err) From 37e2bd91663c064e063640e5aea099bb6dec0ea0 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Thu, 20 Jul 2023 14:28:30 +0800 Subject: [PATCH 12/25] core: update Makefiles --- client/Makefile | 3 +-- genconfig/Makefile | 5 ++--- katzenmint/Makefile | 8 ++----- plugin/Makefile | 37 ++++++++++++++++----------------- server/Makefile | 5 +---- server/cmd/meson-server/main.go | 4 ++-- 6 files changed, 26 insertions(+), 36 deletions(-) diff --git a/client/Makefile b/client/Makefile index 6514b7d..03b04ce 100644 --- a/client/Makefile +++ b/client/Makefile @@ -5,8 +5,7 @@ default: lint test .PHONY: lint lint: - # go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.0 - # $(GOPATH)/bin/golangci-lint run -e gosec ./... --timeout=2m + go vet ./... go fmt ./... go mod tidy diff --git a/genconfig/Makefile b/genconfig/Makefile index 34c4a48..663a3fb 100644 --- a/genconfig/Makefile +++ b/genconfig/Makefile @@ -6,14 +6,13 @@ default: lint test # Exclude S1034: assigning the result of this type assertion to a variable (switch cfg := cfg.(type)) could eliminate type assertions in switch cases .PHONY: lint lint: - # go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.0 - # $(GOPATH)/bin/golangci-lint run -e gosec -e S1034 ./... --timeout 2m + go vet ./... go fmt ./... go mod tidy .PHONY: test test: - go test ./... + go test --race ./... .PHONY: build build: diff --git a/katzenmint/Makefile b/katzenmint/Makefile index f63f90f..c74a940 100644 --- a/katzenmint/Makefile +++ b/katzenmint/Makefile @@ -16,17 +16,13 @@ default: lint test .PHONY: lint lint: - # go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.0 - # $(GOPATH)/bin/golangci-lint run --timeout 2m0s -e gosec ./... + go vet ./... go fmt ./... go mod tidy -# added -race in future (badger fatal error: checkptr: pointer arithmetic result points to invalid allocation) -# https://github.com/golang/go/issues/40917 .PHONY: test test: - go test ./s11n - go test ./ + go test --race ./... .PHONY: setup diff --git a/plugin/Makefile b/plugin/Makefile index bcf0703..fc555fc 100644 --- a/plugin/Makefile +++ b/plugin/Makefile @@ -1,19 +1,18 @@ -GOPATH=$(shell go env GOPATH) - -.PHONY: default -default: lint test - -.PHONY: lint -lint: - # go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.0 - # $(GOPATH)/bin/golangci-lint run -e gosec ./... --timeout 2m - go fmt ./... - go mod tidy - -.PHONY: test -test: - go test ./... - -.PHONY: build -build: - go build ./cmd/meson-plugin +GOPATH=$(shell go env GOPATH) + +.PHONY: default +default: lint test + +.PHONY: lint +lint: + go vet ./... + go fmt ./... + go mod tidy + +.PHONY: test +test: + go test --race ./... + +.PHONY: build +build: + go build ./cmd/meson-plugin diff --git a/server/Makefile b/server/Makefile index 859c315..e447b14 100644 --- a/server/Makefile +++ b/server/Makefile @@ -6,13 +6,10 @@ default: lint test .PHONY: lint lint: - # go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.0 - # $(GOPATH)/bin/golangci-lint run -e gosec ./... --timeout 2m + go vet ./... go fmt ./... go mod tidy -# added -race in future (badger fatal error: checkptr: pointer arithmetic result points to invalid allocation) -# https://github.com/golang/go/issues/40917 .PHONY: test test: go test -tags=$(GOTAGS) ./... diff --git a/server/cmd/meson-server/main.go b/server/cmd/meson-server/main.go index c621275..f7fc7ce 100644 --- a/server/cmd/meson-server/main.go +++ b/server/cmd/meson-server/main.go @@ -90,10 +90,10 @@ func main() { } // Setup the signal handling. - haltCh := make(chan os.Signal) + haltCh := make(chan os.Signal, 1) signal.Notify(haltCh, os.Interrupt, syscall.SIGTERM) // nolint - rotateCh := make(chan os.Signal) + rotateCh := make(chan os.Signal, 1) signal.Notify(rotateCh, syscall.SIGHUP) // nolint // Start up the server. From 839589412a8bcaef7f74a96c7a525ad442c832e0 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Thu, 20 Jul 2023 16:36:53 +0800 Subject: [PATCH 13/25] server: patch race condition in processKaetzchen --- server/Makefile | 2 +- server/internal/provider/kaetzchen/kaetzchen.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/server/Makefile b/server/Makefile index e447b14..5f404af 100644 --- a/server/Makefile +++ b/server/Makefile @@ -12,7 +12,7 @@ lint: .PHONY: test test: - go test -tags=$(GOTAGS) ./... + go test --race -tags=$(GOTAGS) ./... .PHONY: build build: diff --git a/server/internal/provider/kaetzchen/kaetzchen.go b/server/internal/provider/kaetzchen/kaetzchen.go index 1262bfe..c9d96af 100644 --- a/server/internal/provider/kaetzchen/kaetzchen.go +++ b/server/internal/provider/kaetzchen/kaetzchen.go @@ -239,8 +239,9 @@ func (k *KaetzchenWorker) worker() { } func (k *KaetzchenWorker) processKaetzchen(pkt *packet.Packet) { + k.Lock() kaetzchenRequestsTimer = prometheus.NewTimer(kaetzchenRequestsDuration) - defer kaetzchenRequestsTimer.ObserveDuration() + k.Unlock() defer pkt.Dispose() ct, surb, err := packet.ParseForwardPacket(pkt) @@ -287,6 +288,7 @@ func (k *KaetzchenWorker) processKaetzchen(pkt *packet.Packet) { // implementation should have caught this. k.log.Debugf("Kaetzchen message: %v (Has reply but no SURB)", pkt.ID) } + kaetzchenRequestsTimer.ObserveDuration() } func (k *KaetzchenWorker) KaetzchenForPKI() map[string]map[string]interface{} { From 95867688cd6bc8e75fe0be6c3dd23b9e5fac63fc Mon Sep 17 00:00:00 2001 From: sc0vu Date: Fri, 21 Jul 2023 15:25:02 +0800 Subject: [PATCH 14/25] core: update -race flag --- genconfig/Makefile | 2 +- katzenmint/Makefile | 2 +- plugin/Makefile | 2 +- server/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/genconfig/Makefile b/genconfig/Makefile index 663a3fb..c9f9c31 100644 --- a/genconfig/Makefile +++ b/genconfig/Makefile @@ -12,7 +12,7 @@ lint: .PHONY: test test: - go test --race ./... + go test -race ./... .PHONY: build build: diff --git a/katzenmint/Makefile b/katzenmint/Makefile index c74a940..e6eb022 100644 --- a/katzenmint/Makefile +++ b/katzenmint/Makefile @@ -22,7 +22,7 @@ lint: .PHONY: test test: - go test --race ./... + go test -race ./... .PHONY: setup diff --git a/plugin/Makefile b/plugin/Makefile index fc555fc..034127a 100644 --- a/plugin/Makefile +++ b/plugin/Makefile @@ -11,7 +11,7 @@ lint: .PHONY: test test: - go test --race ./... + go test -race ./... .PHONY: build build: diff --git a/server/Makefile b/server/Makefile index 5f404af..a10b1a9 100644 --- a/server/Makefile +++ b/server/Makefile @@ -12,7 +12,7 @@ lint: .PHONY: test test: - go test --race -tags=$(GOTAGS) ./... + go test -race -tags=$(GOTAGS) ./... .PHONY: build build: From b9db80ddc4a1a90d17cdc4edfa570c4a3f72fce4 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Mon, 31 Jul 2023 22:23:33 +0800 Subject: [PATCH 15/25] ci: add go 1.20.x --- .github/workflows/client.yml | 2 +- .github/workflows/katzenmint.yml | 2 +- .github/workflows/plugin.yml | 2 +- .github/workflows/server.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/client.yml b/.github/workflows/client.yml index 7ab65e5..a79ba49 100644 --- a/.github/workflows/client.yml +++ b/.github/workflows/client.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x"] + go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/katzenmint.yml b/.github/workflows/katzenmint.yml index 73206b1..a7a76e8 100644 --- a/.github/workflows/katzenmint.yml +++ b/.github/workflows/katzenmint.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x"] + go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] runs-on: ${{ matrix.os }} steps: - uses: actions/setup-go@v3 diff --git a/.github/workflows/plugin.yml b/.github/workflows/plugin.yml index b83ad78..001acb0 100644 --- a/.github/workflows/plugin.yml +++ b/.github/workflows/plugin.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x"] + go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] runs-on: ${{ matrix.os }} steps: - uses: actions/setup-go@v3 diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml index 0b679cb..b36f54e 100644 --- a/.github/workflows/server.yml +++ b/.github/workflows/server.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x"] + go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] runs-on: ${{ matrix.os }} steps: - uses: actions/setup-go@v3 From dac9199af284f14626ce016b50c80f3b9436e5b2 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Mon, 7 Aug 2023 18:19:20 +0800 Subject: [PATCH 16/25] core: use epoch as expiration of certificate --- client/pkiclient/katzenmint.go | 13 ++++++-- client/pkiclient/katzenmint_test.go | 8 ++--- katzenmint/app.go | 2 +- katzenmint/app_test.go | 2 +- katzenmint/cert/cert.go | 26 ++++++++++++---- katzenmint/cert/ed25519_test.go | 47 +++++++++++++++-------------- katzenmint/cert/ed25519_vectors.go | 9 +++--- katzenmint/s11n/descriptor.go | 32 +++++++++++++++----- katzenmint/s11n/descriptor_test.go | 4 +-- katzenmint/s11n/document.go | 6 ++-- katzenmint/s11n/document_test.go | 4 +-- katzenmint/state.go | 6 ++-- katzenmint/state_test.go | 2 +- katzenmint/testutil/create.go | 2 +- server/internal/pki/pki.go | 6 ++-- 15 files changed, 102 insertions(+), 67 deletions(-) diff --git a/client/pkiclient/katzenmint.go b/client/pkiclient/katzenmint.go index ddfb135..ec8c935 100644 --- a/client/pkiclient/katzenmint.go +++ b/client/pkiclient/katzenmint.go @@ -7,6 +7,7 @@ import ( "encoding/binary" "errors" "fmt" + "math" costypes "github.com/cosmos/cosmos-sdk/store/types" kpki "github.com/hashcloak/Meson/katzenmint" @@ -127,7 +128,7 @@ func (p *PKIClient) GetDoc(ctx context.Context, epoch uint64) (*cpki.Document, [ } // Verify and parse the document - doc, err := s11n.VerifyAndParseDocument(resp.Response.Value) + doc, err := s11n.VerifyAndParseDocument(resp.Response.Value, epoch) if err != nil { return nil, nil, fmt.Errorf("failed to extract doc: %v", err) } @@ -167,7 +168,7 @@ func (p *PKIClient) Post(ctx context.Context, epoch uint64, signingKey *eddsa.Pr } // Make a serialized + signed + serialized descriptor. - signed, err := s11n.SignDescriptor(signingKey, d) + signed, err := s11n.SignDescriptor(signingKey, d, epoch+s11n.CertificateExpiration) if err != nil { return err } @@ -208,7 +209,13 @@ func (p *PKIClient) PostTx(ctx context.Context, tx []byte) (*ctypes.ResultBroadc // Deserialize returns PKI document given the raw bytes. func (p *PKIClient) Deserialize(raw []byte) (*cpki.Document, error) { - return s11n.VerifyAndParseDocument(raw) + // TODO: figure out a better way + return s11n.VerifyAndParseDocument(raw, math.MaxUint64) +} + +// DeserializeWithEpoch returns PKI document given the raw bytes. +func (p *PKIClient) DeserializeWithEpoch(raw []byte, epoch uint64) (*cpki.Document, error) { + return s11n.VerifyAndParseDocument(raw, epoch) } // NewPKIClient create PKI Client from PKI config diff --git a/client/pkiclient/katzenmint_test.go b/client/pkiclient/katzenmint_test.go index 36cfb67..f274f08 100644 --- a/client/pkiclient/katzenmint_test.go +++ b/client/pkiclient/katzenmint_test.go @@ -83,7 +83,7 @@ func TestMockPKIClientGetDocument(t *testing.T) { // create a test document _, docSer := testutil.CreateTestDocument(require, epoch) - testDoc, err := s11n.VerifyAndParseDocument(docSer) + testDoc, err := s11n.VerifyAndParseDocument(docSer, epoch) require.NoError(err) var ( @@ -216,7 +216,7 @@ func TestMockPKIClientPostTx(t *testing.T) { tmtx, ).Run( func(args mock.Arguments) { - parsed, err := s11n.ParseDescriptorWithoutVerify(signed) + parsed, err := s11n.ParseDescriptor(signed, epoch) require.NoError(err) require.Equal(desc.IdentityKey, parsed.IdentityKey) require.Equal(desc.LinkKey, parsed.LinkKey) @@ -259,7 +259,7 @@ func TestDeserialize(t *testing.T) { // create a test document _, docSer := testutil.CreateTestDocument(require, epoch) - testDoc, err := s11n.VerifyAndParseDocument(docSer) + testDoc, err := s11n.VerifyAndParseDocument(docSer, epoch) require.NoError(err) // make the abci query @@ -282,7 +282,7 @@ func TestDeserialize(t *testing.T) { require.NoError(err) require.NotNil(pkiClient) - doc, err := pkiClient.Deserialize(docSer) + doc, err := pkiClient.DeserializeWithEpoch(docSer, epoch) require.NoError(err) require.Equal(doc, testDoc) } diff --git a/katzenmint/app.go b/katzenmint/app.go index 6111068..bd1153f 100644 --- a/katzenmint/app.go +++ b/katzenmint/app.go @@ -111,7 +111,7 @@ func (app *KatzenmintApplication) isTxValid(rawTx []byte) ( err = ErrTxDescInvalidVerifier return } - desc, err = s11n.VerifyAndParseDescriptor(verifier, payload, tx.Epoch) + desc, err = s11n.VerifyAndParseDescriptor(verifier, payload, tx.Epoch, app.state.currentEpoch) if err != nil { err = ErrTxDescFalseVerification return diff --git a/katzenmint/app_test.go b/katzenmint/app_test.go index bf886ea..e692195 100644 --- a/katzenmint/app_test.go +++ b/katzenmint/app_test.go @@ -203,7 +203,7 @@ func TestPostDescriptorAndCommit(t *testing.T) { loaded, _, err := app.state.GetDocument(epoch, app.state.blockHeight-1) require.Nil(err, "Failed to get pki document from state: %+v\n", err) require.NotNil(loaded, "Failed to get pki document from state: wrong key") - _, err = s11n.VerifyAndParseDocument(loaded) + _, err = s11n.VerifyAndParseDocument(loaded, app.state.currentEpoch) require.Nil(err, "Failed to parse pki document: %+v\n", err) // prepare verification metadata (in an old block) diff --git a/katzenmint/cert/cert.go b/katzenmint/cert/cert.go index f35deac..c0c0195 100644 --- a/katzenmint/cert/cert.go +++ b/katzenmint/cert/cert.go @@ -22,7 +22,6 @@ import ( "encoding/binary" "errors" "sort" - "time" "github.com/fxamacker/cbor/v2" ) @@ -109,7 +108,7 @@ type certificate struct { Version uint32 // Expiration is seconds since Unix epoch. - Expiration int64 + Expiration uint64 // KeyType indicates the type of key // that is certified by this certificate. @@ -158,15 +157,16 @@ func (c *certificate) basicCheck() error { } func (c *certificate) sanityCheck() error { - if time.Unix(c.Expiration, 0).Before(time.Now()) { - return ErrCertificateExpired - } + // TODO: find a way to check expiration without http client + // if time.Unix(c.Expiration, 0).Before(time.Now()) { + // return ErrCertificateExpired + // } return c.basicCheck() } // Sign uses the given Signer to create a certificate which // certifies the given data. -func Sign(signer Signer, data []byte, expiration int64) ([]byte, error) { +func Sign(signer Signer, data []byte, expiration uint64) ([]byte, error) { cert := certificate{ Version: CertVersion, Expiration: expiration, @@ -204,6 +204,20 @@ func GetUnsafe(rawCert []byte) ([]byte, error) { return cert.Certified, nil } +// GetCertificate returns the certificate. +func GetCertificate(rawCert []byte) (*certificate, error) { + cert := certificate{} + err := cbor.Unmarshal(rawCert, &cert) + if err != nil { + return nil, ErrImpossibleEncode + } + err = cert.sanityCheck() + if err != nil { + return nil, err + } + return &cert, nil +} + // GetCertified returns the certified data. func GetCertified(rawCert []byte) ([]byte, error) { cert := certificate{} diff --git a/katzenmint/cert/ed25519_test.go b/katzenmint/cert/ed25519_test.go index cfe8d39..4cbee51 100644 --- a/katzenmint/cert/ed25519_test.go +++ b/katzenmint/cert/ed25519_test.go @@ -19,7 +19,6 @@ package cert import ( "bytes" "testing" - "time" "github.com/katzenpost/core/crypto/eddsa" "github.com/katzenpost/core/crypto/rand" @@ -35,15 +34,17 @@ func TestEd25519ExpiredCertificate(t *testing.T) { signingPrivKey, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration six months ago - expiration := time.Now().AddDate(0, -6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certificate, err := Sign(signingPrivKey, ephemeralPrivKey.PublicKey().Bytes(), expiration) - assert.Error(err) + // assert.Error(err) + assert.Nil(err) + assert.NotNil(certificate) - certified, err := Verify(ephemeralPrivKey.PublicKey(), certificate) - assert.Error(err) - assert.Nil(certified) + // certified, err := Verify(ephemeralPrivKey.PublicKey(), certificate) + // assert.Error(err) + // assert.Nil(certified) } func TestEd25519Certificate(t *testing.T) { @@ -55,8 +56,8 @@ func TestEd25519Certificate(t *testing.T) { signingPrivKey, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expires 600 years after unix epoch - expiration := time.Unix(0, 0).AddDate(600, 0, 0).Unix() + // expires 10 epoch + expiration := uint64(10) toSign := ephemeralPrivKey.PublicKey().Bytes() certificate, err := Sign(signingPrivKey, toSign, expiration) @@ -74,8 +75,8 @@ func TestEd25519BadCertificate(t *testing.T) { signingPrivKey, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certified := signingPrivKey.PublicKey().Bytes() certified[3] = 235 // modify the signed data so that the Verify will fail @@ -97,8 +98,8 @@ func TestEd25519WrongCertificate(t *testing.T) { signingPrivKey, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certificate, err := Sign(signingPrivKey, ephemeralPrivKey.PublicKey().Bytes(), expiration) assert.NoError(err) @@ -120,8 +121,8 @@ func TestEd25519MultiSignatureCertificate(t *testing.T) { signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) assert.NoError(err) @@ -158,8 +159,8 @@ func TestEd25519MultiSignatureOrdering(t *testing.T) { signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) // 1 certificate1, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) @@ -203,8 +204,8 @@ func TestEd25519VerifyAll(t *testing.T) { signingPrivKey3, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) assert.NoError(err) @@ -236,8 +237,8 @@ func TestEd25519VerifyThreshold(t *testing.T) { signingPrivKey4, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) assert.NoError(err) @@ -278,8 +279,8 @@ func TestEd25519AddSignature(t *testing.T) { signingPrivKey2, err := eddsa.NewKeypair(rand.Reader) assert.NoError(err) - // expiration in six months - expiration := time.Now().AddDate(0, 6, 0).Unix() + // expires 10 epoch + expiration := uint64(10) certificate, err := Sign(signingPrivKey1, ephemeralPrivKey.PublicKey().Bytes(), expiration) assert.NoError(err) diff --git a/katzenmint/cert/ed25519_vectors.go b/katzenmint/cert/ed25519_vectors.go index c272d65..f8ba444 100644 --- a/katzenmint/cert/ed25519_vectors.go +++ b/katzenmint/cert/ed25519_vectors.go @@ -19,7 +19,6 @@ package cert import ( "encoding/hex" "testing" - "time" "github.com/katzenpost/core/crypto/eddsa" "github.com/stretchr/testify/assert" @@ -68,8 +67,8 @@ func TestEd25519SingleSignatureCertificateVectors(t *testing.T) { } for _, test := range certificateTests { - // expires 600 years after unix epoch - expiration := time.Unix(18934214400, 0).Unix() + // expires 10 epoch + expiration := uint64(10) signingKeyRaw, err := hex.DecodeString(test.in.signingKey) assert.NoError(err) toSign, err := hex.DecodeString(test.in.toSign) @@ -135,8 +134,8 @@ func TestEd25519MultipleSignatureCertificateVectors(t *testing.T) { } for _, test := range certificateTests { - // expires 600 years after unix epoch - expiration := time.Unix(18934214400, 0).Unix() + // expires 10 epoch + expiration := uint64(10) sigKeys := []*eddsa.PrivateKey{} for _, key := range test.in.signingKeys { diff --git a/katzenmint/s11n/descriptor.go b/katzenmint/s11n/descriptor.go index 3579677..27f3c46 100644 --- a/katzenmint/s11n/descriptor.go +++ b/katzenmint/s11n/descriptor.go @@ -22,10 +22,8 @@ import ( "fmt" "net" "strconv" - "time" "github.com/hashcloak/Meson/katzenmint/cert" - "github.com/katzenpost/core/epochtime" "github.com/katzenpost/core/pki" "github.com/katzenpost/core/sphinx/constants" "github.com/ugorji/go/codec" @@ -38,7 +36,8 @@ const ( var ( // CertificateExpiration is the time a descriptor certificate will be valid for. - CertificateExpiration = (epochtime.Period * 3) + (time.Minute * 10) + // 10 epoch by default + CertificateExpiration uint64 = 10 ) type nodeDescriptor struct { @@ -51,7 +50,9 @@ type nodeDescriptor struct { // SignDescriptor signs and serializes the descriptor with the provided signing // key. -func SignDescriptor(signer cert.Signer, base *pki.MixDescriptor) ([]byte, error) { +// TODO: figure out a way to calculate epoch without initialize a http client +// then we can remove expiration from function +func SignDescriptor(signer cert.Signer, base *pki.MixDescriptor, expiration uint64) ([]byte, error) { d := new(nodeDescriptor) d.MixDescriptor = *base d.Version = nodeDescriptorVersion @@ -64,7 +65,6 @@ func SignDescriptor(signer cert.Signer, base *pki.MixDescriptor) ([]byte, error) } // Sign the descriptor. - expiration := time.Now().Add(CertificateExpiration).Unix() signed, err := cert.Sign(signer, payload, expiration) if err != nil { return nil, err @@ -88,8 +88,15 @@ func GetVerifierFromDescriptor(rawDesc []byte) (cert.Verifier, error) { return d.IdentityKey, nil } -func ParseDescriptorWithoutVerify(b []byte) (*pki.MixDescriptor, error) { - payload, err := cert.GetUnsafe(b) +func ParseDescriptor(b []byte, epochNow uint64) (*pki.MixDescriptor, error) { + signedCert, err := cert.GetCertificate(b) + if err != nil { + return nil, err + } + if epochNow > signedCert.Expiration { + return nil, cert.ErrCertificateExpired + } + payload, err := cert.GetCertified(b) if err != nil { return nil, err } @@ -105,7 +112,7 @@ func ParseDescriptorWithoutVerify(b []byte) (*pki.MixDescriptor, error) { // descriptor. MixDescriptors returned from this routine are guaranteed // to have been correctly self signed by the IdentityKey listed in the // MixDescriptor. -func VerifyAndParseDescriptor(verifier cert.Verifier, b []byte, epoch uint64) (*pki.MixDescriptor, error) { +func VerifyAndParseDescriptor(verifier cert.Verifier, b []byte, epoch uint64, epochNow uint64) (*pki.MixDescriptor, error) { signatures, err := cert.GetSignatures(b) if err != nil { return nil, err @@ -120,6 +127,15 @@ func VerifyAndParseDescriptor(verifier cert.Verifier, b []byte, epoch uint64) (* return nil, err } + signedCert, err := cert.GetCertificate(b) + if err != nil { + return nil, err + } + + if epochNow > signedCert.Expiration { + return nil, cert.ErrCertificateExpired + } + // Parse the payload. d := new(nodeDescriptor) dec := codec.NewDecoderBytes(payload, jsonHandle) diff --git a/katzenmint/s11n/descriptor_test.go b/katzenmint/s11n/descriptor_test.go index b09c852..6aaacbe 100644 --- a/katzenmint/s11n/descriptor_test.go +++ b/katzenmint/s11n/descriptor_test.go @@ -70,13 +70,13 @@ func TestDescriptor(t *testing.T) { t.Logf("Descriptor: '%v'", d) // Sign the descriptor. - signed, err := SignDescriptor(identityPriv, d) + signed, err := SignDescriptor(identityPriv, d, debugTestEpoch+CertificateExpiration) require.NoError(err, "SignDescriptor()") t.Logf("signed descriptor: '%v'", signed) // Verify and deserialize the signed descriptor. - dd, err := VerifyAndParseDescriptor(identityPriv.PublicKey(), signed, debugTestEpoch) + dd, err := VerifyAndParseDescriptor(identityPriv.PublicKey(), signed, debugTestEpoch, debugTestEpoch) require.NoError(err, "VerifyAndParseDescriptor()") t.Logf("Deserialized descriptor: '%v'", dd) diff --git a/katzenmint/s11n/document.go b/katzenmint/s11n/document.go index d5dfa17..8c8ba0d 100644 --- a/katzenmint/s11n/document.go +++ b/katzenmint/s11n/document.go @@ -72,7 +72,7 @@ func SerializeDocument(d *Document) ([]byte, error) { return payload, nil } -func VerifyAndParseDocument(payload []byte) (*pki.Document, error) { +func VerifyAndParseDocument(payload []byte, epochNow uint64) (*pki.Document, error) { d := new(Document) dec := codec.NewDecoderBytes(payload, jsonHandle) if err := dec.Decode(d); err != nil { @@ -112,7 +112,7 @@ func VerifyAndParseDocument(payload []byte) (*pki.Document, error) { if err != nil { return nil, err } - desc, err := VerifyAndParseDescriptor(verifier, rawDesc, doc.Epoch) + desc, err := VerifyAndParseDescriptor(verifier, rawDesc, doc.Epoch, epochNow) if err != nil { return nil, err } @@ -125,7 +125,7 @@ func VerifyAndParseDocument(payload []byte) (*pki.Document, error) { if err != nil { return nil, err } - desc, err := VerifyAndParseDescriptor(verifier, rawDesc, doc.Epoch) + desc, err := VerifyAndParseDescriptor(verifier, rawDesc, doc.Epoch, epochNow) if err != nil { return nil, err } diff --git a/katzenmint/s11n/document_test.go b/katzenmint/s11n/document_test.go index 82aa707..cd63cd0 100644 --- a/katzenmint/s11n/document_test.go +++ b/katzenmint/s11n/document_test.go @@ -58,7 +58,7 @@ func genDescriptor(require *require.Assertions, idx int, layer int) (*pki.MixDes err = IsDescriptorWellFormed(d, debugTestEpoch) require.NoError(err, "IsDescriptorWellFormed(good)") - signed, err := SignDescriptor(identityPriv, d) + signed, err := SignDescriptor(identityPriv, d, debugTestEpoch+CertificateExpiration) require.NoError(err, "SignDescriptor()") return d, []byte(signed) @@ -100,7 +100,7 @@ func TestDocument(t *testing.T) { require.NoError(err, "SerializeDocument()") // Validate and deserialize. - ddoc, err := VerifyAndParseDocument([]byte(serialized)) + ddoc, err := VerifyAndParseDocument([]byte(serialized), debugTestEpoch) require.NoError(err, "VerifyAndParseDocument()") require.Equal(doc.Epoch, ddoc.Epoch, "VerifyAndParseDocument(): Epoch") require.Equal(doc.SendRatePerMinute, testSendRate, "VerifyAndParseDocument(): SendRatePerMinute") diff --git a/katzenmint/state.go b/katzenmint/state.go index c01df05..37f8781 100644 --- a/katzenmint/state.go +++ b/katzenmint/state.go @@ -109,7 +109,7 @@ func NewKatzenmintState(kConfig *config.Config, db dbm.DB, dbCacheSize int) *Kat if err != nil { panic(fmt.Errorf("failed to get document (%d): %v", state.currentEpoch-1, err)) } - state.prevDocument, _ = s11n.VerifyAndParseDocument(rawDoc) + state.prevDocument, _ = s11n.VerifyAndParseDocument(rawDoc, state.currentEpoch) return state } @@ -391,7 +391,7 @@ func (s *KatzenmintState) generateDocument() (*document, error) { begin := storageKey(descriptorsBucket, []byte{}, s.currentEpoch) end := storageKey(descriptorsBucket, []byte{}, s.currentEpoch+1) _ = s.tree.IterateRange(begin, end, true, func(key, value []byte) (ret bool) { - desc, err := s11n.ParseDescriptorWithoutVerify(value) + desc, err := s11n.ParseDescriptor(value, s.currentEpoch) // might happened when the data was corrupted if err != nil { // s.tree.Remove(key) @@ -456,7 +456,7 @@ func (s *KatzenmintState) generateDocument() (*document, error) { } // Ensure the document is sane. - pDoc, err := s11n.VerifyAndParseDocument(serialized) + pDoc, err := s11n.VerifyAndParseDocument(serialized, s.currentEpoch) if err != nil { return nil, fmt.Errorf("signed document failed validation: %v", err) } diff --git a/katzenmint/state_test.go b/katzenmint/state_test.go index f6c2096..616edb8 100644 --- a/katzenmint/state_test.go +++ b/katzenmint/state_test.go @@ -233,6 +233,6 @@ func TestDocumentGenerationUponCommit(t *testing.T) { loaded, _, err := state.GetDocument(testEpoch, state.blockHeight-1) require.Nil(err, "Failed to get pki document from state: %+v\n", err) require.NotNil(loaded, "Failed to get pki document from state: wrong key") - _, err = s11n.VerifyAndParseDocument(loaded) + _, err = s11n.VerifyAndParseDocument(loaded, state.currentEpoch) require.Nil(err, "Failed to parse pki document: %+v\n", err) } diff --git a/katzenmint/testutil/create.go b/katzenmint/testutil/create.go index 98b28a9..709c3f2 100644 --- a/katzenmint/testutil/create.go +++ b/katzenmint/testutil/create.go @@ -46,7 +46,7 @@ func CreateTestDescriptor(require *require.Assertions, idx int, layer int, epoch require.NoError(err, "IsDescriptorWellFormed(good)") // Sign the descriptor. - signed, err := s11n.SignDescriptor(identityPriv, desc) + signed, err := s11n.SignDescriptor(identityPriv, desc, epoch+s11n.CertificateExpiration) require.NoError(err, "SignDescriptor()") return desc, signed, *identityPriv } diff --git a/server/internal/pki/pki.go b/server/internal/pki/pki.go index 0e0d6b5..31f6ff8 100644 --- a/server/internal/pki/pki.go +++ b/server/internal/pki/pki.go @@ -352,10 +352,8 @@ func (p *pki) publishDescriptorIfNeeded(pkiCtx context.Context) error { } if till < publishGracePeriod { // check whether the certificate is expired and the network stuck - if p.lastPublishedTime.Unix() > 0 { - now := time.Now() - elapsed := now.Sub(p.lastPublishedTime) - if elapsed > s11n.CertificateExpiration { + if p.lastPublishedEpoch > 0 { + if epoch > 0 && (epoch-p.lastPublishedEpoch) > s11n.CertificateExpiration { // Should we republish epoch + 1? p.log.Debugf("Publish epoch again: %d.", epoch) p.lastPublishedEpoch = 0 From bbf801f35bd8d5ac23bf3117085fa7044e9c31c9 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 8 Aug 2023 15:50:53 +0800 Subject: [PATCH 17/25] server: update for expiration --- server/internal/pki/pki.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/server/internal/pki/pki.go b/server/internal/pki/pki.go index 31f6ff8..c703f37 100644 --- a/server/internal/pki/pki.go +++ b/server/internal/pki/pki.go @@ -352,12 +352,10 @@ func (p *pki) publishDescriptorIfNeeded(pkiCtx context.Context) error { } if till < publishGracePeriod { // check whether the certificate is expired and the network stuck - if p.lastPublishedEpoch > 0 { - if epoch > 0 && (epoch-p.lastPublishedEpoch) > s11n.CertificateExpiration { - // Should we republish epoch + 1? - p.log.Debugf("Publish epoch again: %d.", epoch) - p.lastPublishedEpoch = 0 - } + if p.lastPublishedEpoch > 0 && (epoch > 0 && (epoch-p.lastPublishedEpoch) > s11n.CertificateExpiration) { + // Should we republish epoch + 1? + p.log.Debugf("Publish epoch again: %d.", epoch) + p.lastPublishedEpoch = 0 } else { epoch++ } From 5be093aae1fb00b65fafe79d7cbd3b49cbac534a Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 5 Dec 2023 13:45:04 +0800 Subject: [PATCH 18/25] make: add test-all command --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3d3118a..3aa82d8 100644 --- a/Makefile +++ b/Makefile @@ -11,4 +11,12 @@ build-docker-containers: build-docker-katzenmint build-docker-server .PHONY: clean-docker-images clean-docker-images: - docker rmi -f $$(docker images | grep '^' | awk '{print $$3}') \ No newline at end of file + docker rmi -f $$(docker images | grep '^' | awk '{print $$3}') + +.PHONE: test-all +test-all: + @$(MAKE) $(MAKE_FLAGS) -C client/. test + @$(MAKE) $(MAKE_FLAGS) -C genconfig/. test + @$(MAKE) $(MAKE_FLAGS) -C katzenmint/. test + @$(MAKE) $(MAKE_FLAGS) -C plugin/. test + @$(MAKE) $(MAKE_FLAGS) -C server/. test From 9efe9f483d85726729ed72eaa829ddeed11ad397 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 5 Dec 2023 14:03:23 +0800 Subject: [PATCH 19/25] testnet: clean write file atomic --- testnet/local/cleanup.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testnet/local/cleanup.sh b/testnet/local/cleanup.sh index 36c6870..a9a9c32 100644 --- a/testnet/local/cleanup.sh +++ b/testnet/local/cleanup.sh @@ -47,6 +47,9 @@ clean_katzenmint_dir () { if [ -d $d/katzenmint ]; then rm -rf $d/katzenmint fi; + if [ -d $d/config ]; then + rm -rf $d/config/write-file-atomic* + fi; echo "{ \"height\": \"0\", \"round\": 0, From d8bd26bfe405edcd6487babaa1e3a5c8aac222c4 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 5 Dec 2023 16:18:52 +0800 Subject: [PATCH 20/25] core: patch plugin and server --- katzenmint/s11n/descriptor.go | 6 +++--- plugin/cmd/meson-plugin/main.go | 21 +++++++++------------ server/internal/packet/packet.go | 2 +- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/katzenmint/s11n/descriptor.go b/katzenmint/s11n/descriptor.go index 8f3ef0f..acc8853 100644 --- a/katzenmint/s11n/descriptor.go +++ b/katzenmint/s11n/descriptor.go @@ -36,8 +36,8 @@ const ( var ( // CertificateExpiration is the time a descriptor certificate will be valid for. - // 10 epoch by default - CertificateExpiration uint64 = 10 + // 600 epoch by default + CertificateExpiration uint64 = 600 ) type nodeDescriptor struct { @@ -93,7 +93,7 @@ func ParseDescriptor(b []byte, epochNow uint64) (*pki.MixDescriptor, error) { if err != nil { return nil, err } - if epochNow > signedCert.Expiration { + if (epochNow + 1) > signedCert.Expiration { return nil, cert.ErrCertificateExpired } payload, err := cert.GetCertified(b) diff --git a/plugin/cmd/meson-plugin/main.go b/plugin/cmd/meson-plugin/main.go index 6870b66..1ecf3ca 100644 --- a/plugin/cmd/meson-plugin/main.go +++ b/plugin/cmd/meson-plugin/main.go @@ -135,11 +135,11 @@ func main() { // Ensure that the log directory exists. s, err := os.Stat(logDir) if os.IsNotExist(err) { - fmt.Printf("Log directory '%s' doesn't exist.", logDir) + log.Errorf("Log directory '%s' doesn't exist.", logDir) os.Exit(1) } if !s.IsDir() { - fmt.Println("Log directory must actually be a directory.") + log.Error("Log directory must actually be a directory.") os.Exit(1) } @@ -147,8 +147,7 @@ func main() { logFile := path.Join(logDir, fmt.Sprintf("currency.%d.log", os.Getpid())) f, err := os.Create(logFile) if err != nil { - log.Errorf("Failed to create log file '%v: %v\n'", logFile, err) - log.Error("Exiting") + log.Errorf("Failed to create log file '%v: %v\n'Exiting\n", logFile, err) os.Exit(-1) } logBackend := setupLoggerBackend(level, f) @@ -161,16 +160,14 @@ func main() { // Load config file. cfg, err := config.LoadFile(*cfgFile) if err != nil { - log.Errorf("Failed to load config file '%v: %v\n'", *cfgFile, err) - log.Error("Exiting") + log.Errorf("Failed to load config file '%v: %v\n'Exiting\n", *cfgFile, err) os.Exit(-1) } // Start service. currency, err := proxy.New(cfg) if err != nil { - log.Errorf("Failed to load proxy config: %v\n", err) - log.Error("Exiting") + log.Errorf("Failed to load proxy config: %v\nExiting\n", err) os.Exit(-1) } _requestHandler := func(response http.ResponseWriter, request *http.Request) { @@ -181,10 +178,10 @@ func main() { } server := http.Server{} socketFile := fmt.Sprintf("/tmp/%d.currency.socket", os.Getpid()) + defer os.Remove(socketFile) unixListener, err := net.Listen("unix", socketFile) if err != nil { - log.Errorf("Failed to start server: %v\n", err) - log.Error("Exiting") + log.Errorf("Failed to start server: %v\nExiting\n", err) os.Exit(-1) } http.HandleFunc("/request", _requestHandler) @@ -192,7 +189,7 @@ func main() { fmt.Printf("%s\n", socketFile) err = server.Serve(unixListener) if err != nil { - fmt.Println(err) + log.Errorf("Failed to start server: %v\nExiting\n", err) + os.Exit(-1) } - os.Remove(socketFile) } diff --git a/server/internal/packet/packet.go b/server/internal/packet/packet.go index 3849eef..2dd53cf 100644 --- a/server/internal/packet/packet.go +++ b/server/internal/packet/packet.go @@ -186,7 +186,7 @@ func (pkt *Packet) copyToRaw(b []byte) error { func (pkt *Packet) disposeRaw() { if len(pkt.Raw) == constants.PacketLength { utils.ExplicitBzero(pkt.Raw) - rawPacketPool.Put(&pkt.Raw) // nolint: megacheck + rawPacketPool.Put(pkt.Raw) // nolint: megacheck } pkt.Raw = nil } From 67bd472583704868f23478d46a5e8c4da4eea7f2 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Tue, 5 Dec 2023 16:28:21 +0800 Subject: [PATCH 21/25] sh: update cleanup.sh --- testnet/local/cleanup.sh | 122 ++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/testnet/local/cleanup.sh b/testnet/local/cleanup.sh index a9a9c32..3665277 100644 --- a/testnet/local/cleanup.sh +++ b/testnet/local/cleanup.sh @@ -2,69 +2,71 @@ echo "Clean up data generated when execute scripts..." -NOW=$(TZ=UTC date +"%Y-%m-%dT%H:%M:%S.000000Z") -TITLE="\"genesis_time\"" +# NOW=$(TZ=UTC date +"%Y-%m-%dT%H:%M:%S.000000Z") +# TITLE="\"genesis_time\"" -clean_mix_dir () { - d=$1 - if [ -d $d ]; then - echo "Clean mix data: $d" - if [ -d $d/data ]; then - rm -rf $d/data/* - fi; - fi; -} +# clean_mix_dir () { +# d=$1 +# if [ -d $d ]; then +# echo "Clean mix data: $d" +# if [ -d $d/data ]; then +# rm -rf $d/data/* +# fi; +# fi; +# } -clean_provider_dir () { - d=$1 - if [ -d $d ]; then - echo "Clean provider data: $d" - if [ -d $d/data ]; then - rm -rf $d/data/* - fi; - if [ -f $d/cpu.prof ]; then - rm -rf $d/cpu.prof - fi; - if [ -f $d/mem.prof ]; then - rm -rf $d/mem.prof - fi; - fi; -} +# clean_provider_dir () { +# d=$1 +# if [ -d $d ]; then +# echo "Clean provider data: $d" +# if [ -d $d/data ]; then +# rm -rf $d/data/* +# fi; +# if [ -f $d/cpu.prof ]; then +# rm -rf $d/cpu.prof +# fi; +# if [ -f $d/mem.prof ]; then +# rm -rf $d/mem.prof +# fi; +# fi; +# } -clean_katzenmint_dir () { - d=$1 - if [ -d $d ]; then - echo "Clean katzenmint data: $d" - if [ ! -d $d/data ]; then - mkdir $d/data - fi; - if [ -d $d/data ]; then - rm -rf $d/data/* - fi; - if [ -d $d/kdata ]; then - rm -rf $d/kdata/* - fi; - if [ -d $d/katzenmint ]; then - rm -rf $d/katzenmint - fi; - if [ -d $d/config ]; then - rm -rf $d/config/write-file-atomic* - fi; - echo "{ - \"height\": \"0\", - \"round\": 0, - \"step\": 0 - }" > $d/data/priv_validator_state.json - # Update genesis block time - perl -i -pe"s/$TITLE.*/$TITLE: \"$NOW\",/g" $d/config/genesis.json - fi; -} +# clean_katzenmint_dir () { +# d=$1 +# if [ -d $d ]; then +# echo "Clean katzenmint data: $d" +# if [ ! -d $d/data ]; then +# mkdir $d/data +# fi; +# if [ -d $d/data ]; then +# rm -rf $d/data/* +# fi; +# if [ -d $d/kdata ]; then +# rm -rf $d/kdata/* +# fi; +# if [ -d $d/katzenmint ]; then +# rm -rf $d/katzenmint +# fi; +# if [ -d $d/config ]; then +# rm -rf $d/config/write-file-atomic* +# fi; +# echo "{ +# \"height\": \"0\", +# \"round\": 0, +# \"step\": 0 +# }" > $d/data/priv_validator_state.json +# # Update genesis block time +# perl -i -pe"s/$TITLE.*/$TITLE: \"$NOW\",/g" $d/config/genesis.json +# fi; +# } -for d in conf/* ; do - [ -L "${d%/}" ] && continue - [[ $d =~ ^conf/mix[1-3] ]] && clean_mix_dir $d - [[ $d =~ ^conf/provider[1-3] ]] && clean_provider_dir $d - [[ $d =~ ^conf/node[1-4] ]] && clean_katzenmint_dir $d -done +# for d in conf/* ; do +# [ -L "${d%/}" ] && continue +# [[ $d =~ ^conf/mix[1-3] ]] && clean_mix_dir $d +# [[ $d =~ ^conf/provider[1-3] ]] && clean_provider_dir $d +# [[ $d =~ ^conf/node[1-4] ]] && clean_katzenmint_dir $d +# done + +git checkout HEAD conf echo "Cleaned up!" From e2f6da287982096b57d60a931e70c82c5d5cbc5a Mon Sep 17 00:00:00 2001 From: sc0vu Date: Wed, 6 Dec 2023 10:35:11 +0800 Subject: [PATCH 22/25] make: add build-all and all --- Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Makefile b/Makefile index 3aa82d8..4ced3bd 100644 --- a/Makefile +++ b/Makefile @@ -20,3 +20,18 @@ test-all: @$(MAKE) $(MAKE_FLAGS) -C katzenmint/. test @$(MAKE) $(MAKE_FLAGS) -C plugin/. test @$(MAKE) $(MAKE_FLAGS) -C server/. test + +.PHONE: build-all +build-all: + @$(MAKE) $(MAKE_FLAGS) -C genconfig/. build + @$(MAKE) $(MAKE_FLAGS) -C katzenmint/. build + @$(MAKE) $(MAKE_FLAGS) -C plugin/. build + @$(MAKE) $(MAKE_FLAGS) -C server/. build + +.PHONE: all +all: + @$(MAKE) $(MAKE_FLAGS) -C client/. + @$(MAKE) $(MAKE_FLAGS) -C genconfig/. + @$(MAKE) $(MAKE_FLAGS) -C katzenmint/. + @$(MAKE) $(MAKE_FLAGS) -C plugin/. + @$(MAKE) $(MAKE_FLAGS) -C server/. From c81c5406bd084b8320318b14a7902241ca4da201 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Wed, 6 Dec 2023 11:24:51 +0800 Subject: [PATCH 23/25] ci: bundle most ci together --- .github/workflows/{katzenmint.yml => all.yml} | 31 +++++++------ .github/workflows/client.yml | 24 ---------- .github/workflows/plugin.yml | 46 ------------------- .github/workflows/server.yml | 46 ------------------- 4 files changed, 16 insertions(+), 131 deletions(-) rename .github/workflows/{katzenmint.yml => all.yml} (51%) delete mode 100644 .github/workflows/client.yml delete mode 100644 .github/workflows/plugin.yml delete mode 100644 .github/workflows/server.yml diff --git a/.github/workflows/katzenmint.yml b/.github/workflows/all.yml similarity index 51% rename from .github/workflows/katzenmint.yml rename to .github/workflows/all.yml index a7a76e8..c923785 100644 --- a/.github/workflows/katzenmint.yml +++ b/.github/workflows/all.yml @@ -1,4 +1,4 @@ -name: Katzenmint +name: All on: ["push", "pull_request"] @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] + go: ["1.19.x", "1.20.x", "1.21.x"] runs-on: ${{ matrix.os }} steps: - uses: actions/setup-go@v3 @@ -19,28 +19,29 @@ jobs: - uses: actions/checkout@v3 - - name: "Test katzenmint" + - name: "Test all" run: | - cd katzenmint - make + make test-all - - name: "Build katzenmint" + - name: "Build all" run: | - cd katzenmint - make build + make build-all mkdir dist - mv katzenmint dist + mv katzenmint/katzenmint dist + mv server/meson-server dist + mv plugin/meson-plugin dist + mv genconfig/genconfig dist - if: runner.os == 'macOS' - name: "Setup katzenmint filename" - run: echo "ZIPNAME=katzenmint_darwin_${{ matrix.go }}" >> $GITHUB_ENV + name: "Setup filename" + run: echo "ZIPNAME=meson_darwin_${{ matrix.go }}" >> $GITHUB_ENV - if: runner.os == 'Linux' - name: "Setup katzenmint filename" - run: echo "ZIPNAME=katzenmint_linux_${{ matrix.go }}" >> $GITHUB_ENV + name: "Setup filename" + run: echo "ZIPNAME=meson_linux_${{ matrix.go }}" >> $GITHUB_ENV - - name: Archive katzenmint + - name: Archive all uses: actions/upload-artifact@v3 with: name: ${{ env.ZIPNAME }} - path: katzenmint/dist + path: dist diff --git a/.github/workflows/client.yml b/.github/workflows/client.yml deleted file mode 100644 index f34a835..0000000 --- a/.github/workflows/client.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Client - -on: ["push", "pull_request"] - -jobs: - - build: - strategy: - matrix: - os: ["ubuntu-latest", "macOS-latest"] - go: ["1.19.x", "1.20.x"] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: ${{ matrix.go }} - - - name: Lint and Test client - run: | - cd client - make diff --git a/.github/workflows/plugin.yml b/.github/workflows/plugin.yml deleted file mode 100644 index 001acb0..0000000 --- a/.github/workflows/plugin.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Plugin - -on: ["push", "pull_request"] - -jobs: - - build_and_test: - name: "Run tests and build artifacts" - strategy: - matrix: - os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/setup-go@v3 - name: "Install Golang" - with: - go-version: ${{ matrix.go }} - - - uses: actions/checkout@v3 - - - name: "Test plugin" - run: | - cd plugin - make - - - name: "Build plugin" - run: | - cd plugin - make build - mkdir dist - mv meson-plugin dist - - - if: runner.os == 'macOS' - name: "Setup plugin filename" - run: echo "ZIPNAME=meson_plugin_darwin_${{ matrix.go }}" >> $GITHUB_ENV - - - if: runner.os == 'Linux' - name: "Setup plugin filename" - run: echo "ZIPNAME=meson_plugin_linux_${{ matrix.go }}" >> $GITHUB_ENV - - - name: Archive plugin - uses: actions/upload-artifact@v3 - with: - name: ${{ env.ZIPNAME }} - path: plugin/dist diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml deleted file mode 100644 index b36f54e..0000000 --- a/.github/workflows/server.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Server - -on: ["push", "pull_request"] - -jobs: - - build_and_test: - name: "Run tests and build artifacts" - strategy: - matrix: - os: ["ubuntu-latest", "macOS-latest"] - go: ["1.17.x", "1.18.x", "1.19.x", "1.20.x"] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/setup-go@v3 - name: "Install Golang" - with: - go-version: ${{ matrix.go }} - - - uses: actions/checkout@v3 - - - name: "Test server" - run: | - cd server - make - - - name: "Build server" - run: | - cd server - make build - mkdir dist - mv meson-server dist - - - if: runner.os == 'macOS' - name: "Setup server filename" - run: echo "ZIPNAME=meson_server_darwin_${{ matrix.go }}" >> $GITHUB_ENV - - - if: runner.os == 'Linux' - name: "Setup server filename" - run: echo "ZIPNAME=meson_server_linux_${{ matrix.go }}" >> $GITHUB_ENV - - - name: Archive server - uses: actions/upload-artifact@v3 - with: - name: ${{ env.ZIPNAME }} - path: server/dist From 250ae07110a3abed6e81a162a9ac7fd1cb255dd3 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Wed, 6 Dec 2023 11:27:09 +0800 Subject: [PATCH 24/25] ci: use go 1.21.x --- .github/workflows/all.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml index c923785..10ca8ce 100644 --- a/.github/workflows/all.yml +++ b/.github/workflows/all.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macOS-latest"] - go: ["1.19.x", "1.20.x", "1.21.x"] + go: ["1.21.x"] runs-on: ${{ matrix.os }} steps: - uses: actions/setup-go@v3 From d174a009eb0a3c61e9f283ac8046649b5814a8f8 Mon Sep 17 00:00:00 2001 From: sc0vu Date: Wed, 6 Dec 2023 11:31:55 +0800 Subject: [PATCH 25/25] server: update test --- server/config/config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/config/config_test.go b/server/config/config_test.go index 7821894..787742f 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -28,7 +28,7 @@ func TestConfig(t *testing.T) { _, err := Load(nil) require.Error(err, "no Load() with nil config") - require.EqualError(err, "No nil buffer as config file") + require.EqualError(err, "no nil buffer as config file") const basicConfig = `# A basic configuration example. [server]