gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet-go] 01/02: Started revocation implementation.


From: gnunet
Subject: [gnunet-go] 01/02: Started revocation implementation.
Date: Wed, 19 Feb 2020 11:06:24 +0100

This is an automated email from the git hooks/post-receive script.

bernd-fix pushed a commit to branch master
in repository gnunet-go.

commit db8edd2189c526a79039661844314081739010e1
Author: Bernd Fix <address@hidden>
AuthorDate: Mon Feb 17 12:34:45 2020 +0100

    Started revocation implementation.
---
 src/cmd/pow-test/main.go             |  48 ++++++++
 src/gnunet/message/factory.go        |  12 ++
 src/gnunet/message/msg_revocation.go | 181 +++++++++++++++++++++++++++
 src/gnunet/service/gns/module.go     |  10 ++
 src/gnunet/service/revocation/pow.go | 231 +++++++++++++++++++++++++++++++++++
 5 files changed, 482 insertions(+)

diff --git a/src/cmd/pow-test/main.go b/src/cmd/pow-test/main.go
new file mode 100644
index 0000000..4b74b6e
--- /dev/null
+++ b/src/cmd/pow-test/main.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+       "flag"
+       "fmt"
+       "log"
+
+       "gnunet/service/revocation"
+
+       "github.com/bfix/gospel/crypto/ed25519"
+       "github.com/bfix/gospel/math"
+)
+
+func main() {
+       var (
+               quiet bool
+               bits  int
+       )
+       flag.IntVar(&bits, "b", 25, "Number of leading zero bits")
+       flag.BoolVar(&quiet, "q", false, "Be quiet")
+       flag.Parse()
+       fmt.Printf("Leading zeros required: %d\n", bits)
+
+       // generate a random key pair
+       pkey, _ := ed25519.NewKeypair()
+
+       // initialize RevData structure
+       rd := revocation.NewRevData(0, pkey)
+
+       // pre-set difficulty
+       difficulty := math.TWO.Pow(512 - bits).Sub(math.ONE)
+
+       var count uint64 = 0
+       for {
+               result, err := rd.Compute()
+               if err != nil {
+                       log.Fatal(err)
+               }
+               //fmt.Printf("Nonce=%d, Result=(%d) %v\n", rd.GetNonce(), 
result.BitLen(), result)
+               if result.Cmp(difficulty) < 0 {
+                       break
+               }
+               count++
+               rd.Next()
+       }
+       fmt.Printf("PoW found after %d iterations:\n", count)
+       fmt.Printf("--> Nonce=%d\n", rd.GetNonce())
+}
diff --git a/src/gnunet/message/factory.go b/src/gnunet/message/factory.go
index f6a8783..e6e6e73 100644
--- a/src/gnunet/message/factory.go
+++ b/src/gnunet/message/factory.go
@@ -81,6 +81,18 @@ func NewEmptyMessage(msgType uint16) (Message, error) {
                return NewNamecacheCacheMsg(nil), nil
        case NAMECACHE_BLOCK_CACHE_RESPONSE:
                return NewNamecacheCacheResponseMsg(), nil
+
+       //------------------------------------------------------------------
+       // Revocation
+       //------------------------------------------------------------------
+       case REVOCATION_QUERY:
+               return NewRevocationQueryMsg(nil), nil
+       case REVOCATION_QUERY_RESPONSE:
+               return NewRevocationQueryResponseMsg(true), nil
+       case REVOCATION_REVOKE:
+               return NewRevocationRevokeMsg(0, nil, nil), nil
+       case REVOCATION_REVOKE_RESPONSE:
+               return NewRevocationRevokeResponseMsg(false), nil
        }
        return nil, errors.New(fmt.Sprintf("Unknown message type %d", msgType))
 }
diff --git a/src/gnunet/message/msg_revocation.go 
b/src/gnunet/message/msg_revocation.go
new file mode 100644
index 0000000..fea727c
--- /dev/null
+++ b/src/gnunet/message/msg_revocation.go
@@ -0,0 +1,181 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go 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.
+//
+// gnunet-go 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 <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package message
+
+import (
+       "fmt"
+
+       "gnunet/crypto"
+       "gnunet/enums"
+       "gnunet/util"
+
+       "github.com/bfix/gospel/crypto/ed25519"
+)
+
+//----------------------------------------------------------------------
+// REVOCATION_QUERY
+//----------------------------------------------------------------------
+
+// RevocationQueryMsg
+type RevocationQueryMsg struct {
+       MsgSize  uint16 `order:"big"` // total size of message
+       MsgType  uint16 `order:"big"` // REVOCATION_QUERY (636)
+       Reserved uint32 `order:"big"` // Reserved for future use
+       Zone     []byte `size:"32"`   // Zone that is to be checked for 
revocation
+}
+
+// NewRevocationQueryMsg creates a new message for a given zone.
+func NewRevocationQueryMsg(zone *ed25519.PublicKey) *RevocationQueryMsg {
+       msg := &RevocationQueryMsg{
+               MsgSize:  40,
+               MsgType:  REVOCATION_QUERY,
+               Reserved: 0,
+               Zone:     make([]byte, 32),
+       }
+       if zone != nil {
+               copy(msg.Zone, zone.Bytes())
+       }
+       return msg
+}
+
+// String returns a human-readable representation of the message.
+func (m *RevocationQueryMsg) String() string {
+       return fmt.Sprintf("RevocationQueryMsg{zone=%s}", 
util.EncodeBinaryToString(m.Zone))
+}
+
+// Header returns the message header in a separate instance.
+func (msg *RevocationQueryMsg) Header() *MessageHeader {
+       return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
+
+//----------------------------------------------------------------------
+// REVOCATION_QUERY_RESPONSE
+//----------------------------------------------------------------------
+
+// RevocationQueryResponseMsg
+type RevocationQueryResponseMsg struct {
+       MsgSize uint16 `order:"big"` // total size of message
+       MsgType uint16 `order:"big"` // REVOCATION_QUERY_RESPONSE (637)
+       Valid   uint32 `order:"big"` // revoked(0), valid(1)
+}
+
+// NewRevocationQueryResponseMsg creates a new response for a query.
+func NewRevocationQueryResponseMsg(revoked bool) *RevocationQueryResponseMsg {
+       valid := 1
+       if revoked {
+               valid = 0
+       }
+       return &RevocationQueryResponseMsg{
+               MsgSize: 8,
+               MsgType: REVOCATION_QUERY_RESPONSE,
+               Valid:   uint32(valid),
+       }
+}
+
+// String returns a human-readable representation of the message.
+func (m *RevocationQueryResponseMsg) String() string {
+       return fmt.Sprintf("RevocationQueryResponseMsg{valid=%d}", m.Valid)
+}
+
+// Header returns the message header in a separate instance.
+func (msg *RevocationQueryResponseMsg) Header() *MessageHeader {
+       return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
+
+//----------------------------------------------------------------------
+// REVOCATION_REVOKE
+//----------------------------------------------------------------------
+
+// RevocationRevokeMsg
+type RevocationRevokeMsg struct {
+       MsgSize   uint16                   `order:"big"` // total size of 
message
+       MsgType   uint16                   `order:"big"` // REVOCATION_QUERY 
(636)
+       Reserved  uint32                   `order:"big"` // Reserved for future 
use
+       PoW       uint64                   `order:"big"` // Proof-of-work: 
nonce that satisfy condition
+       Signature []byte                   `size:"64"`   // Signature of the 
revocation.
+       Purpose   *crypto.SignaturePurpose // Size and purpose of signature (8 
bytes)
+       ZoneKey   []byte                   `size:"32"` // Zone key to be revoked
+}
+
+// NewRevocationRevokeMsg creates a new message for a given zone.
+func NewRevocationRevokeMsg(pow uint64, zoneKey *ed25519.PublicKey, sig 
*ed25519.EcSignature) *RevocationRevokeMsg {
+       msg := &RevocationRevokeMsg{
+               MsgSize:   120,
+               MsgType:   REVOCATION_REVOKE,
+               Reserved:  0,
+               PoW:       pow,
+               Signature: make([]byte, 64),
+               Purpose: &crypto.SignaturePurpose{
+                       Size:    40,
+                       Purpose: enums.SIG_REVOCATION,
+               },
+               ZoneKey: make([]byte, 32),
+       }
+       if zoneKey != nil {
+               copy(msg.ZoneKey, zoneKey.Bytes())
+       }
+       if sig != nil {
+               copy(msg.Signature, sig.Bytes())
+       }
+       return msg
+}
+
+// String returns a human-readable representation of the message.
+func (m *RevocationRevokeMsg) String() string {
+       return fmt.Sprintf("RevocationRevokeMsg{pow=%d,zone=%s}", m.PoW, 
util.EncodeBinaryToString(m.ZoneKey))
+}
+
+// Header returns the message header in a separate instance.
+func (msg *RevocationRevokeMsg) Header() *MessageHeader {
+       return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
+
+//----------------------------------------------------------------------
+// REVOCATION_REVOKE_RESPONSE
+//----------------------------------------------------------------------
+
+// RevocationRevokeResponseMsg
+type RevocationRevokeResponseMsg struct {
+       MsgSize uint16 `order:"big"` // total size of message
+       MsgType uint16 `order:"big"` // REVOCATION_QUERY_RESPONSE (637)
+       Success uint32 `order:"big"` // Revoke successful?
+}
+
+// NewRevocationRevokeResponseMsg creates a new response for a query.
+func NewRevocationRevokeResponseMsg(success bool) *RevocationRevokeResponseMsg 
{
+       status := 0
+       if success {
+               status = 1
+       }
+       return &RevocationRevokeResponseMsg{
+               MsgSize: 8,
+               MsgType: REVOCATION_QUERY_RESPONSE,
+               Success: uint32(status),
+       }
+}
+
+// String returns a human-readable representation of the message.
+func (m *RevocationRevokeResponseMsg) String() string {
+       return fmt.Sprintf("RevocationRevokeResponseMsg{success=%v}", m.Success 
== 1)
+}
+
+// Header returns the message header in a separate instance.
+func (msg *RevocationRevokeResponseMsg) Header() *MessageHeader {
+       return &MessageHeader{msg.MsgSize, msg.MsgType}
+}
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go
index 5626432..e8d8847 100644
--- a/src/gnunet/service/gns/module.go
+++ b/src/gnunet/service/gns/module.go
@@ -280,6 +280,16 @@ func (gns *GNSModule) ResolveRelative(labels []string, 
pkey *ed25519.PublicKey,
                        set.AddRecord(inst.rec)
                }
        }
+
+       // if the result set is not empty, add all supplemental records we are 
not
+       // asking for explicitly.
+       if set.Count > 0 {
+               for _, rec := range records {
+                       if !kind.HasType(int(rec.Type)) && 
(int(rec.Flags)&enums.GNS_FLAG_SUPPL) != 0 {
+                               set.AddRecord(rec)
+                       }
+               }
+       }
        return
 }
 
diff --git a/src/gnunet/service/revocation/pow.go 
b/src/gnunet/service/revocation/pow.go
new file mode 100644
index 0000000..368b4e4
--- /dev/null
+++ b/src/gnunet/service/revocation/pow.go
@@ -0,0 +1,231 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+//
+// gnunet-go 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.
+//
+// gnunet-go 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 <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package revocation
+
+import (
+       "bytes"
+       "crypto/sha256"
+       "crypto/sha512"
+       "encoding/binary"
+       "sync"
+
+       "gnunet/crypto"
+       "gnunet/util"
+
+       "github.com/bfix/gospel/crypto/ed25519"
+       "github.com/bfix/gospel/data"
+       "github.com/bfix/gospel/math"
+       "golang.org/x/crypto/hkdf"
+       "golang.org/x/crypto/scrypt"
+)
+
+//----------------------------------------------------------------------
+// Revocation data
+//----------------------------------------------------------------------
+
+// RevData is the revocation data structure (wire format)
+type RevData struct {
+       Nonce   uint64 `order:"big"` // start with this nonce value
+       ZoneKey []byte `size:"32"`   // public zone key to be revoked
+
+       // transient attributes (not serialized)
+       blob []byte // binary representation of serialized data
+}
+
+// NewRevData creates a RevData instance for the given arguments.
+func NewRevData(nonce uint64, zoneKey *ed25519.PublicKey) *RevData {
+       rd := &RevData{
+               Nonce:   nonce,
+               ZoneKey: make([]byte, 32),
+       }
+       copy(rd.ZoneKey, zoneKey.Bytes())
+       blob, err := data.Marshal(rd)
+       if err != nil {
+               return nil
+       }
+       rd.blob = blob
+       return rd
+}
+
+// GetNonce returns the last checked nonce value
+func (r *RevData) GetNonce() uint64 {
+       if r.blob != nil {
+               var val uint64
+               binary.Read(bytes.NewReader(r.blob[:8]), binary.BigEndian, &val)
+               r.Nonce = val
+       }
+       return r.Nonce
+}
+
+// Next selects the next nonce to be tested.
+func (r *RevData) Next() {
+       var incr func(pos int)
+       incr = func(pos int) {
+               r.blob[pos]++
+               if r.blob[pos] != 0 || pos == 0 {
+                       return
+               }
+               incr(pos - 1)
+       }
+       incr(7)
+}
+
+// Compute calculates the current result for a RevData content.
+// The result is returned as a big integer value.
+func (r *RevData) Compute() (*math.Int, error) {
+
+       // generate key material
+       k, err := scrypt.Key(r.blob, []byte("gnunet-revocation-proof-of-work"), 
2, 8, 2, 64)
+       if err != nil {
+               return nil, err
+       }
+
+       // generate keys
+       skey := crypto.NewSymmetricKey()
+       copy(skey.AESKey, k[:32])
+       copy(skey.TwofishKey, k[32:])
+
+       // generate initialization vector
+       iv := crypto.NewSymmetricIV()
+       prk := hkdf.Extract(sha512.New, k[:32], 
[]byte("gnunet-proof-of-work-ivAES!"))
+       rdr := hkdf.Expand(sha256.New, prk, 
[]byte("gnunet-revocation-proof-of-work"))
+       rdr.Read(iv.AESIv)
+       prk = hkdf.Extract(sha512.New, k[32:], 
[]byte("gnunet-proof-of-work-ivFISH"))
+       rdr = hkdf.Expand(sha256.New, prk, 
[]byte("gnunet-revocation-proof-of-work"))
+       rdr.Read(iv.TwofishIv)
+
+       // perform encryption
+       enc, err := crypto.SymmetricEncrypt(r.blob, skey, iv)
+       if err != nil {
+               return nil, err
+       }
+
+       // compute result
+       result, err := scrypt.Key(enc, 
[]byte("gnunet-revocation-proof-of-work"), 2, 8, 2, 64)
+       return math.NewIntFromBytes(result), nil
+}
+
+//----------------------------------------------------------------------
+// Command types for Worker
+//----------------------------------------------------------------------
+
+// StartCmd starts the PoW calculation beginng at given nonce. If a
+// revocation is initiated the first time, the nonce is 0. If the computation
+// was interrupted (because the revocation service was shutting down), the
+// computation can resume for the next unchecked nonce value.
+// see: StartResponse
+type StartCmd struct {
+       ID   int      // Command identifier (to relate responses)
+       task *RevData // RevData instance to be started
+}
+
+// PauseCmd temporarily pauses the calculation of a PoW.
+// see: PauseResponse
+type PauseCmd struct {
+       ID     int // Command identifier (to relate responses)
+       taskID int // identifier for PoW task
+}
+
+// ResumeCmd resumes a paused PoW calculation.
+// see: ResumeResponse
+type ResumeCmd struct {
+       ID     int // Command identifier (to relate responses)
+       taskID int // identifier for PoW task
+}
+
+// BreakCmd interrupts a running PoW calculation
+type BreakCmd struct {
+       ID     int // Command identifier (to relate responses)
+       taskID int // identifier for PoW task
+}
+
+//----------------------------------------------------------------------
+// Response types for Worker
+//----------------------------------------------------------------------
+
+// StartResponse is a reply to the StartCmd message
+type StartResponse struct {
+       ID     int   // Command identifier (to relate responses)
+       taskID int   // identifier for PoW task
+       err    error // error code (nil on success)
+}
+
+// PauseResponse is a reply to the PauseCmd message
+type PauseResponse struct {
+       ID  int   // Command identifier (to relate responses)
+       err error // error code (nil on success)
+}
+
+// ResumeResponse is a reply to the ResumeCmd message
+type ResumeResponse struct {
+       ID  int   // Command identifier (to relate responses)
+       err error // error code (nil on success)
+}
+
+// BreakResponse is a reply to the BreakCmd message
+type BreakResponse struct {
+       ID    int    // Command identifier (to relate responses)
+       Nonce uint64 // last checked nonce value
+}
+
+//----------------------------------------------------------------------
+// Worker instance
+//----------------------------------------------------------------------
+
+// Task represents a currently active PoW calculation
+type Task struct {
+       ID     int
+       rev    *RevData
+       active bool
+}
+
+// Worker is the revocation worker. It is responsible to manage ad schedule
+// the proof-of-work tasks for revocations.
+type Worker struct {
+       tasks map[int]*Task
+       wg    *sync.WaitGroup
+}
+
+func NewWorker() *Worker {
+       return &Worker{
+               tasks: make(map[int]*Task),
+               wg:    new(sync.WaitGroup),
+       }
+}
+
+func (w *Worker) Run(wg *sync.WaitGroup, cmdCh chan interface{}, responseCh 
chan interface{}) {
+       defer wg.Done()
+       for {
+               select {
+               case cmd := <-cmdCh:
+                       switch x := cmd.(type) {
+                       case *StartCmd:
+                               task := &Task{
+                                       ID:     util.NextID(),
+                                       rev:    x.task,
+                                       active: true,
+                               }
+                               w.tasks[task.ID] = task
+                       }
+
+               default:
+                       // compute a single round of currently active tasks
+               }
+       }
+}

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]