From 07814e5014eb2fa9c0f9ddb95d9be80c2e8ae077 Mon Sep 17 00:00:00 2001 From: Niko Marmeladkov Date: Wed, 1 Jul 2026 15:02:58 +0300 Subject: [PATCH] Add OpRegister: cert-only registration without PoW New flow: register -> OpRegister(pubKey) -> OpIdentity(number+cert). Reconnect: OpGetChallenge -> OpAuthCert(cert+sig). PoW eliminated from client flow. --- internal/server/server.go | 41 +++++++++++++++++++++++++++++++++++++++ pkg/types/opcode.go | 1 + 2 files changed, 42 insertions(+) diff --git a/internal/server/server.go b/internal/server/server.go index 3361623..5f8ccf1 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -217,6 +217,8 @@ func (s *Server) handleStream(ctx context.Context, stream *quic.Stream, sess *Se s.handleReroll(sess) case types.OpAuthCert: s.handleAuthCert(sess, frame.Payload) + case types.OpRegister: + s.handleRegister(sess, frame.Payload) case types.OpDial: if !sess.IsAuthenticated() { sendOpError(st, types.ErrInvalidRequest, "not authenticated") @@ -367,6 +369,45 @@ func (s *Server) handleAuthCert(sess *Session, payload []byte) { zap.String("number", ident.Number)) } +func (s *Server) handleRegister(sess *Session, payload []byte) { + if len(payload) < 32 { + sendOpError(sess.Stream(), types.ErrInvalidRequest, "invalid pubkey") + return + } + + var pubKey [32]byte + copy(pubKey[:], payload[:32]) + + if _, err := s.identMgr.GetByPubKey(pubKey); err == nil { + sendOpError(sess.Stream(), types.ErrInvalidRequest, "already registered") + return + } + + ident, err := s.identMgr.Allocate(pubKey) + if err != nil { + sendOpError(sess.Stream(), types.ErrInternal, err.Error()) + return + } + + certDER, err := s.ca.IssueCert(ident.Number, ed25519.PublicKey(pubKey[:]), s.cfg.CA.Validity) + if err != nil { + sendOpError(sess.Stream(), types.ErrInternal, "cert issuance failed") + return + } + ident.CertDER = certDER + + sess.Authenticate(ident.Number, pubKey, certDER) + s.Register(sess, ident.Number) + + payload = marshalIdentityResponse(ident.Number, certDER, s.ca.CACertPEM()) + if st := sess.Stream(); st != nil { + st.WriteFrame(byte(types.OpIdentity), payload) + } + + s.logger.Info("Client registered", + zap.String("number", ident.Number)) +} + func (s *Server) handleReroll(sess *Session) { if !sess.IsAuthenticated() { sendOpError(sess.Stream(), types.ErrInvalidRequest, "not authenticated") diff --git a/pkg/types/opcode.go b/pkg/types/opcode.go index 144df9f..97c5855 100644 --- a/pkg/types/opcode.go +++ b/pkg/types/opcode.go @@ -9,6 +9,7 @@ const ( OpIdentity OpCode = 0x04 OpReroll OpCode = 0x05 OpAuthCert OpCode = 0x06 + OpRegister OpCode = 0x07 OpDial OpCode = 0x10 OpRing OpCode = 0x11