skeleton function

pull/76/head
alok 6 years ago
parent 85633ef482
commit c90d4fdcde
  1. 7
      identitychain/identitychain.go
  2. 21
      pow/LICENSE
  3. 57
      pow/README.md
  4. 128
      pow/api.go
  5. 56
      pow/api_test.go
  6. 25
      pow/example_test.go
  7. 78
      pow/sha2bday.go

@ -20,7 +20,6 @@ var identityPerBlock = 100000
type IdentityChain struct { type IdentityChain struct {
//Identities []*IdentityBlock //No need to have the identity block as of now //Identities []*IdentityBlock //No need to have the identity block as of now
Identities []*node.Node Identities []*node.Node
PendingIdentities []*node.Node
log log.Logger log log.Logger
Peer p2p.Peer Peer p2p.Peer
SelectedIdentitites []*node.Node SelectedIdentitites []*node.Node
@ -31,7 +30,6 @@ type IdentityChain struct {
CurrentEpochStartTime int64 CurrentEpochStartTime int64
NumberOfShards int NumberOfShards int
NumberOfNodesInShard int NumberOfNodesInShard int
PowMap map[p2p.Peer]string
} }
func seekRandomNumber(EpochNum int, SelectedIdentitites []*node.Node) int { func seekRandomNumber(EpochNum int, SelectedIdentitites []*node.Node) int {
@ -73,6 +71,11 @@ func (IDC *IdentityChain) BroadCastNewConfiguration() {
} }
//BroadCast Peer Infor to Node
func (IDC *IdentityChain) SendPeerInfo(Node node) {
return
}
//CreateShardAssignment //CreateShardAssignment
func (IDC *IdentityChain) CreateShardAssignment() { func (IDC *IdentityChain) CreateShardAssignment() {
num := seekRandomNumber(IDC.EpochNum, IDC.SelectedIdentitites) num := seekRandomNumber(IDC.EpochNum, IDC.SelectedIdentitites)

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Bas Westerbaan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -1,57 +0,0 @@
go-pow
======
`go-pow` is a simple Go package to add (asymmetric) *Proof of Work* to your service.
To create a Proof-of-Work request (with difficulty 5), use `pow.NewRequest`:
```go
req := pow.NewRequest(5, someRandomNonce)
```
This returns a string like `sha2bday-5-c29tZSByYW5kb20gbm9uY2U`,
which can be passed on to the client.
The client fulfils the proof of work by running `pow.Fulfil`:
```go
proof, _ := pow.Fulfil(req, []byte("some bound data"))
```
The client returns the proof (in this case `AAAAAAAAAAMAAAAAAAAADgAAAAAAAAAb`)
to the server, which can check it is indeed a valid proof of work, by running:
``` go
ok, _ := pow.Check(req, proof, []byte("some bound data"))
```
Notes
-----
1. There should be at least sufficient randomness in either the `nonce` passed to
`NewRequest` or the `data` passed to `Fulfil` and `Check`.
Thus it is fine to use the same bound `data` for every client, if every client
get a different `nonce` in its proof-of-work request.
It is also fine to use the same `nonce` in the proof-of-work request,
if every client is (by the encapsulating protocol) forced to use
different bound `data`.
2. The work to fulfil a request scales exponentially in the difficulty parameter.
The work to check it proof is correct remains constant:
```
Check on Difficulty=5 500000 2544 ns/op
Check on Difficulty=10 500000 2561 ns/op
Check on Difficulty=15 500000 2549 ns/op
Check on Difficulty=20 500000 2525 ns/op
Fulfil on Difficulty=5 100000 15725 ns/op
Fulfil on Difficulty=10 30000 46808 ns/op
Fulfil on Difficulty=15 2000 955606 ns/op
Fulfil on Difficulty=20 200 6887722 ns/op
```
To do
-----
- Support for [equihash](https://www.cryptolux.org/index.php/Equihash) would be nice.
- Port to Python, Java, Javascript, ...
- Parallelize.

@ -1,128 +0,0 @@
// Create and fulfill proof of work requests.
package pow
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
)
type Algorithm string
const (
Sha2BDay Algorithm = "sha2bday"
)
// Represents a proof-of-work request.
type Request struct {
// The requested algorithm
Alg Algorithm
// The requested difficulty
Difficulty uint32
// Nonce to diversify the request
Nonce []byte
}
// Represents a completed proof-of-work
type Proof struct {
buf []byte
}
// Convenience function to create a new sha3bday proof-of-work request
// as a string
func NewRequest(difficulty uint32, nonce []byte) string {
req := Request{
Difficulty: difficulty,
Nonce: nonce,
Alg: Sha2BDay,
}
s, _ := req.MarshalText()
return string(s)
}
func (proof Proof) MarshalText() ([]byte, error) {
return []byte(base64.RawStdEncoding.EncodeToString(proof.buf)), nil
}
func (proof *Proof) UnmarshalText(buf []byte) error {
var err error
proof.buf, err = base64.RawStdEncoding.DecodeString(string(buf))
return err
}
func (req Request) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%s-%d-%s",
req.Alg,
req.Difficulty,
string(base64.RawStdEncoding.EncodeToString(req.Nonce)))), nil
}
func (req *Request) UnmarshalText(buf []byte) error {
bits := strings.SplitN(string(buf), "-", 3)
if len(bits) != 3 {
return fmt.Errorf("There should be two dashes in a PoW request")
}
alg := Algorithm(bits[0])
if alg != Sha2BDay {
return fmt.Errorf("%s: unsupported algorithm", bits[0])
}
req.Alg = alg
diff, err := strconv.Atoi(bits[1])
if err != nil {
return err
}
req.Difficulty = uint32(diff)
req.Nonce, err = base64.RawStdEncoding.DecodeString(bits[2])
return err
}
// Convenience function to check whether a proof of work is fulfilled
func Check(request, proof string, data []byte) (bool, error) {
var req Request
var prf Proof
err := req.UnmarshalText([]byte(request))
if err != nil {
return false, err
}
err = prf.UnmarshalText([]byte(proof))
if err != nil {
return false, err
}
return prf.Check(req, data), nil
}
// Fulfil the proof-of-work request.
func (req *Request) Fulfil(data []byte) Proof {
switch req.Alg {
case Sha2BDay:
return Proof{fulfilSha2BDay(req.Nonce, req.Difficulty, data)}
default:
panic("No such algorithm")
}
}
// Convenience function to fulfil the proof of work request
func Fulfil(request string, data []byte) (string, error) {
var req Request
err := req.UnmarshalText([]byte(request))
if err != nil {
return "", err
}
proof := req.Fulfil(data)
s, _ := proof.MarshalText()
return string(s), nil
}
// Check whether the proof is ok
func (proof *Proof) Check(req Request, data []byte) bool {
switch req.Alg {
case Sha2BDay:
return checkSha2BDay(proof.buf, req.Nonce, data, req.Difficulty)
default:
panic("No such algorithm")
}
}

@ -1,56 +0,0 @@
package pow
import (
"testing"
)
func TestSha2BDay(t *testing.T) {
nonce := []byte{1, 2, 3, 4, 5}
data := []byte{2, 2, 3, 4, 5}
r := NewRequest(5, nonce)
proof, err := Fulfil(r, data)
if err != nil {
t.Fatalf("Fulfil: %v", err)
}
ok, err := Check(r, proof, data)
if err != nil {
t.Fatalf("Check: %v", err)
}
if !ok {
t.Fatalf("Proof of work should be ok")
}
ok, err = Check(r, proof, nonce)
if err != nil {
t.Fatalf("Check: %v", err)
}
if ok {
t.Fatalf("Proof of work should not be ok")
}
}
func BenchmarkCheck5(b *testing.B) { benchmarkCheck(5, b) }
func BenchmarkCheck10(b *testing.B) { benchmarkCheck(10, b) }
func BenchmarkCheck15(b *testing.B) { benchmarkCheck(15, b) }
func BenchmarkCheck20(b *testing.B) { benchmarkCheck(20, b) }
func benchmarkCheck(diff uint32, b *testing.B) {
req := NewRequest(diff, []byte{1, 2, 3, 4, 5})
prf, _ := Fulfil(req, []byte{6, 7, 8, 9})
b.ResetTimer()
for n := 0; n < b.N; n++ {
Check(req, prf, []byte{6, 7, 8, 9})
}
}
func BenchmarkFulfil5(b *testing.B) { benchmarkFulfil(5, b) }
func BenchmarkFulfil10(b *testing.B) { benchmarkFulfil(10, b) }
func BenchmarkFulfil15(b *testing.B) { benchmarkFulfil(15, b) }
func BenchmarkFulfil20(b *testing.B) { benchmarkFulfil(20, b) }
func benchmarkFulfil(diff uint32, b *testing.B) {
req := NewRequest(diff, []byte{1, 2, 3, 4, 5})
b.ResetTimer()
for n := 0; n < b.N; n++ {
Fulfil(req, []byte{6, 7, 8, 9})
}
}

@ -1,25 +0,0 @@
package pow_test
import (
"fmt" // imported as pow
"github.com/simple-rules/harmony-benchmark/pow"
)
func Example() {
// Create a proof of work request with difficulty 5
req := pow.NewRequest(5, []byte("some random nonce"))
fmt.Printf("req: %s\n", req)
// Fulfil the proof of work
proof, _ := pow.Fulfil(req, []byte("some bound data"))
fmt.Printf("proof: %s\n", proof)
// Check if the proof is correct
ok, _ := pow.Check(req, proof, []byte("some bound data"))
fmt.Printf("check: %v", ok)
// Output: req: sha2bday-5-c29tZSByYW5kb20gbm9uY2U
// proof: AAAAAAAAAAMAAAAAAAAADgAAAAAAAAAb
// check: true
}

@ -1,78 +0,0 @@
package pow
import (
"bytes"
"crypto/sha256"
"encoding/binary"
)
func checkSha2BDay(proof []byte, nonce, data []byte, diff uint32) bool {
if len(proof) != 24 {
return false
}
prefix1 := proof[:8]
prefix2 := proof[8:16]
prefix3 := proof[16:]
if bytes.Equal(prefix1, prefix2) || bytes.Equal(prefix2, prefix3) ||
bytes.Equal(prefix1, prefix3) {
return false
}
resBuf := make([]byte, 32)
h := sha256.New()
h.Write(prefix1)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res1 := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
h.Reset()
h.Write(prefix2)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res2 := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
h.Reset()
h.Write(prefix3)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res3 := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
return res1 == res2 && res2 == res3
}
func fulfilSha2BDay(nonce []byte, diff uint32, data []byte) []byte {
// TODO make multithreaded if the difficulty is high enough.
// For light proof-of-work requests, the overhead of parallelizing is
// not worth it.
type Pair struct {
First, Second uint64
}
var i uint64 = 1
prefix := make([]byte, 8)
resBuf := make([]byte, 32)
lut := make(map[uint64]Pair)
h := sha256.New()
for {
binary.BigEndian.PutUint64(prefix, i)
h.Write(prefix)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
pair, ok := lut[res]
if ok {
if pair.Second != 0 {
ret := make([]byte, 24)
binary.BigEndian.PutUint64(ret, pair.First)
binary.BigEndian.PutUint64(ret[8:], pair.Second)
copy(ret[16:], prefix)
return ret
}
lut[res] = Pair{First: pair.First, Second: i}
} else {
lut[res] = Pair{First: i}
}
h.Reset()
i++
}
}
Loading…
Cancel
Save