[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.