aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-08-08 11:28:57 +0800
committerGitHub <noreply@github.com>2018-08-08 11:28:57 +0800
commita418ea95c0f5afb50cbb78aedecc68373353d06e (patch)
tree79bee8ef152f58c0b3bbcbe38d4dd537050b72aa
parent3a929b656b6bd5846849fd98dc29ff761db97ed3 (diff)
downloaddexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.gz
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.bz2
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.lz
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.xz
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.tar.zst
dexon-consensus-a418ea95c0f5afb50cbb78aedecc68373353d06e.zip
crypto: Add crypto module. (#34)
-rw-r--r--.circleci/config.yml1
-rw-r--r--.gitignore1
-rw-r--r--GNUmakefile19
-rw-r--r--Gopkg.toml4
-rw-r--r--core/blocklattice.go2
-rw-r--r--core/consensus-timestamp.go10
-rw-r--r--core/consensus-timestamp_test.go2
-rw-r--r--core/crypto.go58
-rw-r--r--core/crypto_test.go116
-rw-r--r--core/types/block.go36
-rw-r--r--crypto/eth/eth.go99
-rw-r--r--crypto/eth/eth_test.go79
-rw-r--r--crypto/interfaces.go42
-rw-r--r--crypto/utils.go30
-rw-r--r--crypto/utils_test.go52
15 files changed, 534 insertions, 17 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 7611454..1f681e5 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -27,6 +27,7 @@ jobs:
key: v1-vendor-{{ .Branch }}-{{ checksum "Gopkg.lock" }}
paths:
- vendor
+ - run: make eth-dep
- run: make lint
- run: make vet
- run: make test
diff --git a/.gitignore b/.gitignore
index 83fee03..ef110dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,4 +20,5 @@
vendor
build
simulation/kubernetes/build
+.dep
diff --git a/GNUmakefile b/GNUmakefile
index 1680919..ab39a5c 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -50,9 +50,22 @@ all: $(COMPONENTS)
$(foreach component, $(COMPONENTS), $(eval $(call BUILD_RULE,$(component))))
-pre-build:
-
-pre-submit: check-format lint test vet
+pre-build: eth-dep
+
+pre-submit: eth-dep check-format lint test vet
+
+eth-dep:
+ @rm -rf vendor/github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1
+ @if [ ! -d .dep/libsecp256k1 ]; then \
+ git init .dep/libsecp256k1; \
+ cd .dep/libsecp256k1; \
+ git remote add origin https://github.com/ethereum/go-ethereum.git; \
+ git config core.sparsecheckout true; \
+ echo "crypto/secp256k1/libsecp256k1/*" >> .git/info/sparse-checkout; \
+ cd ../../; \
+ fi
+ @cd .dep/libsecp256k1; git pull --depth=1 origin master; cd ../../
+ @cp -r .dep/libsecp256k1/crypto/secp256k1/libsecp256k1 vendor/github.com/ethereum/go-ethereum/crypto/secp256k1
format:
@go fmt `go list ./... | grep -v 'vendor'`
diff --git a/Gopkg.toml b/Gopkg.toml
index 708d991..7d58335 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -34,6 +34,10 @@
version = "1.2.2"
[[constraint]]
+ name = "github.com/ethereum/go-ethereum"
+ version = "1.8.13"
+
+[[constraint]]
branch = "master"
name = "github.com/syndtr/goleveldb"
diff --git a/core/blocklattice.go b/core/blocklattice.go
index f94cc9a..0f5fc11 100644
--- a/core/blocklattice.go
+++ b/core/blocklattice.go
@@ -542,7 +542,7 @@ func (l *BlockLattice) totalOrdering(b *types.Block) {
panic(err)
}
for _, block := range blocksReady {
- l.app.DeliverBlock(block.Hash, block.ConsensusTime)
+ l.app.DeliverBlock(block.Hash, block.ConsensusInfo.Timestamp)
}
}
diff --git a/core/consensus-timestamp.go b/core/consensus-timestamp.go
index e9b5cce..ab904fb 100644
--- a/core/consensus-timestamp.go
+++ b/core/consensus-timestamp.go
@@ -72,17 +72,19 @@ func (ct *consensusTimestamp) processBlocks(blocks []*types.Block) (
return
} else if block.Hash == mainChain[idxMainChain].Hash {
rightMainChainIdx = idx
- blocksWithTimestamp[idx].ConsensusTime, err = ct.getMedianTime(block)
+ blocksWithTimestamp[idx].ConsensusInfo.Timestamp, err =
+ ct.getMedianTime(block)
if err != nil {
return
}
// Process Non-MainChain blocks.
if rightMainChainIdx > leftMainChainIdx {
for idx, timestamp := range interpoTime(
- blocksWithTimestamp[leftMainChainIdx].ConsensusTime,
- blocksWithTimestamp[rightMainChainIdx].ConsensusTime,
+ blocksWithTimestamp[leftMainChainIdx].ConsensusInfo.Timestamp,
+ blocksWithTimestamp[rightMainChainIdx].ConsensusInfo.Timestamp,
rightMainChainIdx-leftMainChainIdx-1) {
- blocksWithTimestamp[leftMainChainIdx+idx+1].ConsensusTime = timestamp
+ blocksWithTimestamp[leftMainChainIdx+idx+1].ConsensusInfo.Timestamp =
+ timestamp
}
}
leftMainChainIdx = idx
diff --git a/core/consensus-timestamp_test.go b/core/consensus-timestamp_test.go
index 8a82080..aeba00a 100644
--- a/core/consensus-timestamp_test.go
+++ b/core/consensus-timestamp_test.go
@@ -79,7 +79,7 @@ func fillBlocksTimestamps(blocks []*types.Block, validatorNum int,
func extractTimestamps(blocks []*types.Block) []time.Time {
timestamps := make([]time.Time, len(blocks))
for idx, block := range blocks {
- timestamps[idx] = block.ConsensusTime
+ timestamps[idx] = block.ConsensusInfo.Timestamp
}
return timestamps
}
diff --git a/core/crypto.go b/core/crypto.go
new file mode 100644
index 0000000..679b045
--- /dev/null
+++ b/core/crypto.go
@@ -0,0 +1,58 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+ "encoding/binary"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
+)
+
+func hashCompactionChainAck(block *types.Block) (common.Hash, error) {
+ binaryTime, err := block.ConsensusInfo.Timestamp.MarshalBinary()
+ if err != nil {
+ return common.Hash{}, err
+ }
+ binaryHeight := make([]byte, 8)
+ binary.LittleEndian.PutUint64(binaryHeight, block.ConsensusInfo.Height)
+ hash := crypto.Keccak256Hash(
+ block.ConsensusInfoParentHash[:],
+ binaryTime,
+ binaryHeight)
+ return hash, nil
+}
+
+func signCompactionChainAck(block *types.Block,
+ prv crypto.PrivateKey) (crypto.Signature, error) {
+ hash, err := hashCompactionChainAck(block)
+ if err != nil {
+ return crypto.Signature{}, err
+ }
+ return prv.Sign(hash)
+}
+
+func verifyCompactionChainAckSignature(pubkey crypto.PublicKey,
+ ackingBlock *types.Block, sig crypto.Signature) (bool, error) {
+ hash, err := hashCompactionChainAck(ackingBlock)
+ if err != nil {
+ return false, err
+ }
+ return pubkey.VerifySignature(hash, sig), nil
+}
diff --git a/core/crypto_test.go b/core/crypto_test.go
new file mode 100644
index 0000000..0ee28e4
--- /dev/null
+++ b/core/crypto_test.go
@@ -0,0 +1,116 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+ "testing"
+ "time"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto/eth"
+ "github.com/stretchr/testify/suite"
+)
+
+type CryptoTestSuite struct {
+ suite.Suite
+}
+
+func (s *CryptoTestSuite) newBlock(prevBlock *types.Block) *types.Block {
+ if prevBlock == nil {
+ return &types.Block{
+ Hash: common.NewRandomHash(),
+ ConsensusInfo: types.ConsensusInfo{
+ Timestamp: time.Now(),
+ Height: 0,
+ },
+ }
+ }
+ parentHash, err := hashCompactionChainAck(prevBlock)
+ s.Require().Nil(err)
+ return &types.Block{
+ Hash: common.NewRandomHash(),
+ ConsensusInfoParentHash: parentHash,
+ CompactionChainAck: types.CompactionChainAck{
+ AckingBlockHash: prevBlock.Hash,
+ },
+ ConsensusInfo: types.ConsensusInfo{
+ Timestamp: time.Now(),
+ Height: prevBlock.ConsensusInfo.Height + 1,
+ },
+ }
+}
+
+func (s *CryptoTestSuite) generateCompactionChain(
+ length int, prv crypto.PrivateKey) []*types.Block {
+ blocks := make([]*types.Block, length)
+ var prevBlock *types.Block
+ for idx := range blocks {
+ block := s.newBlock(prevBlock)
+ blocks[idx] = block
+ var err error
+ if idx > 0 {
+ block.ConsensusInfoParentHash, err = hashCompactionChainAck(blocks[idx-1])
+ s.Require().Nil(err)
+ block.CompactionChainAck.ConsensusSignature, err =
+ signCompactionChainAck(blocks[idx-1], prv)
+ s.Require().Nil(err)
+ }
+ }
+ return blocks
+}
+
+func (s *CryptoTestSuite) TestSignature() {
+ prv, err := eth.NewPrivateKey()
+ pub := prv.PublicKey()
+ s.Require().Nil(err)
+ blocks := s.generateCompactionChain(10, prv)
+ blockMap := make(map[common.Hash]*types.Block)
+ for _, block := range blocks {
+ blockMap[block.Hash] = block
+ }
+ for _, block := range blocks {
+ if block.ConsensusInfo.Height == 0 {
+ continue
+ }
+ ackingBlock, exist := blockMap[block.CompactionChainAck.AckingBlockHash]
+ s.Require().True(exist)
+ s.True(ackingBlock.ConsensusInfo.Height == block.ConsensusInfo.Height-1)
+ hash, err := hashCompactionChainAck(ackingBlock)
+ s.Require().Nil(err)
+ s.Equal(hash, block.ConsensusInfoParentHash)
+ s.True(verifyCompactionChainAckSignature(
+ pub, ackingBlock, block.CompactionChainAck.ConsensusSignature))
+ }
+ // Modify Block.ConsensusTime and verify signature again.
+ for _, block := range blocks {
+ block.ConsensusInfo.Timestamp = time.Time{}
+ if block.ConsensusInfo.Height == 0 {
+ continue
+ }
+ ackingBlock, exist := blockMap[block.CompactionChainAck.AckingBlockHash]
+ s.Require().True(exist)
+ s.False(verifyCompactionChainAckSignature(
+ pub, ackingBlock, block.CompactionChainAck.ConsensusSignature))
+ }
+}
+
+func TestCrypto(t *testing.T) {
+ suite.Run(t, new(CryptoTestSuite))
+}
diff --git a/core/types/block.go b/core/types/block.go
index 56b456c..8a27ab0 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -23,6 +23,7 @@ import (
"time"
"github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
)
// Status represents the block process state.
@@ -36,16 +37,35 @@ const (
BlockStatusFinal
)
+// CompactionChainAck represents the acking to the compaction chain.
+type CompactionChainAck struct {
+ AckingBlockHash common.Hash `json:"acking_block_hash"`
+ // Signature is the signature of the hash value of
+ // Block.ConsensusInfoParentHash and Block.ConsensusInfo.
+ ConsensusSignature crypto.Signature `json:"consensus_signature"`
+}
+
+// ConsensusInfo represents the consensus information on the compaction chain.
+type ConsensusInfo struct {
+ Timestamp time.Time `json:"timestamp"`
+ Height uint64 `json:"height"`
+}
+
// Block represents a single event broadcasted on the network.
type Block struct {
- ProposerID ValidatorID `json:"proposer_id"`
- ParentHash common.Hash `json:"parent_hash"`
- Hash common.Hash `json:"hash"`
- Height uint64 `json:"height"`
- Timestamps map[ValidatorID]time.Time `json:"timestamps"`
- Acks map[common.Hash]struct{} `json:"acks"`
- ConsensusTime time.Time `json:"consensus_time"`
- ConsensusHeight uint64 `json:"consensus_height"`
+ ProposerID ValidatorID `json:"proposer_id"`
+ ParentHash common.Hash `json:"parent_hash"`
+ Hash common.Hash `json:"hash"`
+ Height uint64 `json:"height"`
+ Timestamps map[ValidatorID]time.Time `json:"timestamps"`
+ Acks map[common.Hash]struct{} `json:"acks"`
+ CompactionChainAck CompactionChainAck `json:"compaction_chain_ack"`
+
+ ConsensusInfo ConsensusInfo `json:"consensus_info"`
+ // ConsensusInfoParentHash is the hash value of Block.ConsensusInfoParentHash
+ // and Block.ConsensusInfo, where Block is the previous block on
+ // the compaction chain.
+ ConsensusInfoParentHash common.Hash `json:"consensus_info_parent_hash"`
Ackeds map[common.Hash]struct{} `json:"-"`
AckedValidators map[ValidatorID]struct{} `json:"-"`
diff --git a/crypto/eth/eth.go b/crypto/eth/eth.go
new file mode 100644
index 0000000..cb20d7d
--- /dev/null
+++ b/crypto/eth/eth.go
@@ -0,0 +1,99 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package eth
+
+import (
+ "crypto/ecdsa"
+
+ ethcrypto "github.com/ethereum/go-ethereum/crypto"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/crypto"
+)
+
+// PrivateKey represents a private key structure used in geth and implments
+// Crypto.PrivateKey interface.
+type PrivateKey struct {
+ privateKey ecdsa.PrivateKey
+ publicKey PublicKey
+}
+
+// PublicKey represents a public key structure used in geth and implements
+// Crypto.PublicKey interface.
+type PublicKey struct {
+ publicKey []byte
+}
+
+// NewPrivateKey creates a new PrivateKey structure.
+func NewPrivateKey() (*PrivateKey, error) {
+ key, err := ethcrypto.GenerateKey()
+ if err != nil {
+ return nil, err
+ }
+ return &PrivateKey{
+ privateKey: *key,
+ publicKey: *newPublicKey(key),
+ }, nil
+}
+
+// newPublicKey creates a new PublicKey structure.
+func newPublicKey(prvKey *ecdsa.PrivateKey) *PublicKey {
+ return &PublicKey{
+ publicKey: ethcrypto.CompressPubkey(&prvKey.PublicKey),
+ }
+}
+
+// DecompressPubkey parses a public key in the 33-byte compressed format.
+func DecompressPubkey(pubkey []byte) (PublicKey, error) {
+ _, err := ethcrypto.DecompressPubkey(pubkey)
+ return PublicKey{
+ publicKey: pubkey,
+ }, err
+}
+
+// PublicKey returns the public key associate this private key.
+func (prv *PrivateKey) PublicKey() crypto.PublicKey {
+ return prv.publicKey
+}
+
+// Sign calculates an ECDSA signature.
+//
+// This function is susceptible to chosen plaintext attacks that can leak
+// information about the private key that is used for signing. Callers must
+// be aware that the given hash cannot be chosen by an adversery. Common
+// solution is to hash any input before calculating the signature.
+//
+// The produced signature is in the [R || S || V] format where V is 0 or 1.
+func (prv *PrivateKey) Sign(hash common.Hash) (sig crypto.Signature, err error) {
+ s, err := ethcrypto.Sign(hash[:], &prv.privateKey)
+ // Magic!
+ sig = crypto.Signature(s[:64])
+ return
+}
+
+// VerifySignature checks that the given public key created signature over hash.
+// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
+// The signature should have the 64 byte [R || S] format.
+func (pub PublicKey) VerifySignature(hash common.Hash, signature crypto.Signature) bool {
+ return ethcrypto.VerifySignature(pub.publicKey, hash[:], signature)
+}
+
+// Compress encodes a public key to the 33-byte compressed format.
+func (pub PublicKey) Compress() []byte {
+ return pub.publicKey
+}
diff --git a/crypto/eth/eth_test.go b/crypto/eth/eth_test.go
new file mode 100644
index 0000000..b09297e
--- /dev/null
+++ b/crypto/eth/eth_test.go
@@ -0,0 +1,79 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package eth
+
+import (
+ "testing"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/stretchr/testify/suite"
+)
+
+type ETHCryptoTestSuite struct {
+ suite.Suite
+}
+
+func (s *ETHCryptoTestSuite) TestSignature() {
+ prv1, err := NewPrivateKey()
+ s.Require().Nil(err)
+ hash1 := common.NewRandomHash()
+ hash2 := common.NewRandomHash()
+
+ // Test that same private key should produce same signature.
+ sig11, err := prv1.Sign(hash1)
+ s.Require().Nil(err)
+ sig112, err := prv1.Sign(hash1)
+ s.Require().Nil(err)
+ s.Equal(sig11, sig112)
+
+ // Test that different private key should produce different signature.
+ prv2, err := NewPrivateKey()
+ s.Require().Nil(err)
+ sig21, err := prv2.Sign(hash1)
+ s.Require().Nil(err)
+ s.NotEqual(sig11, sig21)
+
+ // Test that different hash should produce different signature.
+ sig12, err := prv1.Sign(hash2)
+ s.Require().Nil(err)
+ s.NotEqual(sig11, sig12)
+
+ // Test VerifySignature with correct public key.
+ pub1, ok := prv1.PublicKey().(PublicKey)
+ s.Require().True(ok)
+ s.True(pub1.VerifySignature(hash1, sig11))
+
+ // Test VerifySignature with wrong hash.
+ s.False(pub1.VerifySignature(hash2, sig11))
+ // Test VerifySignature with wrong signature.
+ s.False(pub1.VerifySignature(hash1, sig21))
+ // Test VerifySignature with wrong public key.
+ pub2 := prv2.PublicKey()
+ s.False(pub2.VerifySignature(hash1, sig11))
+
+ // Test compress and decompress of public key.
+ compressPub1 := pub1.Compress()
+ decompressPub1, err := DecompressPubkey(compressPub1)
+ s.Require().Nil(err)
+ s.Equal(pub1, decompressPub1)
+ s.True(decompressPub1.VerifySignature(hash1, sig11))
+}
+
+func TestCrypto(t *testing.T) {
+ suite.Run(t, new(ETHCryptoTestSuite))
+}
diff --git a/crypto/interfaces.go b/crypto/interfaces.go
new file mode 100644
index 0000000..015ff40
--- /dev/null
+++ b/crypto/interfaces.go
@@ -0,0 +1,42 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package crypto
+
+import (
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+)
+
+// Signature is the basic signature type in DEXON.
+type Signature []byte
+
+// PrivateKey describes the asymmetric cryptography interface that interacts
+// with the private key.
+type PrivateKey interface {
+ // PublicKey returns the public key associate this private key.
+ PublicKey() PublicKey
+
+ // Sign calculates a signature.
+ Sign(hash common.Hash) (sig Signature, err error)
+}
+
+// PublicKey describes the asymmetric cryptography interface that interacts
+// with the public key.
+type PublicKey interface {
+ // VerifySignature checks that the given public key created signature over hash.
+ VerifySignature(hash common.Hash, signature Signature) bool
+}
diff --git a/crypto/utils.go b/crypto/utils.go
new file mode 100644
index 0000000..5534ece
--- /dev/null
+++ b/crypto/utils.go
@@ -0,0 +1,30 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package crypto
+
+import (
+ "github.com/ethereum/go-ethereum/crypto"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+)
+
+// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
+// converting it to an internal Hash data structure.
+func Keccak256Hash(data ...[]byte) (h common.Hash) {
+ return common.Hash(crypto.Keccak256Hash(data...))
+}
diff --git a/crypto/utils_test.go b/crypto/utils_test.go
new file mode 100644
index 0000000..977027a
--- /dev/null
+++ b/crypto/utils_test.go
@@ -0,0 +1,52 @@
+// Copyright 2018 The dexon-consensus-core Authors
+// This file is part of the dexon-consensus-core library.
+//
+// The dexon-consensus-core library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus-core library 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 Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus-core library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package crypto
+
+import (
+ "encoding/hex"
+ "testing"
+
+ "github.com/stretchr/testify/suite"
+)
+
+type CryptoTestSuite struct {
+ suite.Suite
+}
+
+func (s *CryptoTestSuite) TestHash() {
+ cases := []struct {
+ input string
+ output string
+ }{
+ {"DEXON ROCKS!",
+ "1a3f3a424aaa464e51b693585bba3a0c439d5f1ad3b5868e46d9f830225983bd"},
+ {"Dexon Foundation",
+ "25ed4237aa978bfe706cc11c7a46a95de1a46302faea7ff6e900b03fa2b7b480"},
+ {"INFINITELY SCALABLE AND LOW-LATENCY",
+ "ed3384c58a434fbc0bc887a85659eddf997e7da978ab66565ac865f995b77cf1"},
+ }
+ for _, testcase := range cases {
+ hash := Keccak256Hash([]byte(testcase.input))
+ output := hex.EncodeToString(hash[:])
+ s.Equal(testcase.output, output)
+ }
+}
+
+func TestCrypto(t *testing.T) {
+ suite.Run(t, new(CryptoTestSuite))
+}