From a418ea95c0f5afb50cbb78aedecc68373353d06e Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Wed, 8 Aug 2018 11:28:57 +0800 Subject: crypto: Add crypto module. (#34) --- .circleci/config.yml | 1 + .gitignore | 1 + GNUmakefile | 19 ++++++- Gopkg.toml | 4 ++ core/blocklattice.go | 2 +- core/consensus-timestamp.go | 10 ++-- core/consensus-timestamp_test.go | 2 +- core/crypto.go | 58 ++++++++++++++++++++ core/crypto_test.go | 116 +++++++++++++++++++++++++++++++++++++++ core/types/block.go | 36 +++++++++--- crypto/eth/eth.go | 99 +++++++++++++++++++++++++++++++++ crypto/eth/eth_test.go | 79 ++++++++++++++++++++++++++ crypto/interfaces.go | 42 ++++++++++++++ crypto/utils.go | 30 ++++++++++ crypto/utils_test.go | 52 ++++++++++++++++++ 15 files changed, 534 insertions(+), 17 deletions(-) create mode 100644 core/crypto.go create mode 100644 core/crypto_test.go create mode 100644 crypto/eth/eth.go create mode 100644 crypto/eth/eth_test.go create mode 100644 crypto/interfaces.go create mode 100644 crypto/utils.go create mode 100644 crypto/utils_test.go 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 @@ -33,6 +33,10 @@ name = "github.com/stretchr/testify" 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 +// . + +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 +// . + +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 +// . + +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 +// . + +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 +// . + +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 +// . + +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 +// . + +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)) +} -- cgit v1.2.3