diff options
Diffstat (limited to 'vendor/github.com/tangerine-network/tangerine-consensus/core/utils/crypto.go')
-rw-r--r-- | vendor/github.com/tangerine-network/tangerine-consensus/core/utils/crypto.go | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/vendor/github.com/tangerine-network/tangerine-consensus/core/utils/crypto.go b/vendor/github.com/tangerine-network/tangerine-consensus/core/utils/crypto.go new file mode 100644 index 000000000..1f85e94b6 --- /dev/null +++ b/vendor/github.com/tangerine-network/tangerine-consensus/core/utils/crypto.go @@ -0,0 +1,376 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus 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 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 library. If not, see +// <http://www.gnu.org/licenses/>. + +package utils + +import ( + "bytes" + "encoding/binary" + + "github.com/tangerine-network/tangerine-consensus/common" + "github.com/tangerine-network/tangerine-consensus/core/crypto" + "github.com/tangerine-network/tangerine-consensus/core/types" + typesDKG "github.com/tangerine-network/tangerine-consensus/core/types/dkg" +) + +func hashWitness(witness *types.Witness) (common.Hash, error) { + binaryHeight := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryHeight, witness.Height) + return crypto.Keccak256Hash( + binaryHeight, + witness.Data), nil +} + +// HashBlock generates hash of a types.Block. +func HashBlock(block *types.Block) (common.Hash, error) { + hashPosition := HashPosition(block.Position) + binaryTimestamp, err := block.Timestamp.UTC().MarshalBinary() + if err != nil { + return common.Hash{}, err + } + binaryWitness, err := hashWitness(&block.Witness) + if err != nil { + return common.Hash{}, err + } + + hash := crypto.Keccak256Hash( + block.ProposerID.Hash[:], + block.ParentHash[:], + hashPosition[:], + binaryTimestamp[:], + block.PayloadHash[:], + binaryWitness[:]) + return hash, nil +} + +// VerifyBlockSignature verifies the signature of types.Block. +func VerifyBlockSignature(b *types.Block) (err error) { + payloadHash := crypto.Keccak256Hash(b.Payload) + if payloadHash != b.PayloadHash { + err = ErrIncorrectHash + return + } + return VerifyBlockSignatureWithoutPayload(b) +} + +// VerifyBlockSignatureWithoutPayload verifies the signature of types.Block but +// does not check if PayloadHash is correct. +func VerifyBlockSignatureWithoutPayload(b *types.Block) (err error) { + hash, err := HashBlock(b) + if err != nil { + return + } + if hash != b.Hash { + err = ErrIncorrectHash + return + } + pubKey, err := crypto.SigToPub(b.Hash, b.Signature) + if err != nil { + return + } + if !b.ProposerID.Equal(types.NewNodeID(pubKey)) { + err = ErrIncorrectSignature + return + } + return + +} + +// HashVote generates hash of a types.Vote. +func HashVote(vote *types.Vote) common.Hash { + binaryPeriod := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryPeriod, vote.Period) + + hashPosition := HashPosition(vote.Position) + + hash := crypto.Keccak256Hash( + vote.ProposerID.Hash[:], + vote.BlockHash[:], + binaryPeriod, + hashPosition[:], + vote.PartialSignature.Signature[:], + []byte{byte(vote.Type)}, + ) + return hash +} + +// VerifyVoteSignature verifies the signature of types.Vote. +func VerifyVoteSignature(vote *types.Vote) (bool, error) { + hash := HashVote(vote) + pubKey, err := crypto.SigToPub(hash, vote.Signature) + if err != nil { + return false, err + } + if vote.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +func hashCRS(block *types.Block, crs common.Hash) common.Hash { + hashPos := HashPosition(block.Position) + if block.Position.Round < dkgDelayRound { + return crypto.Keccak256Hash(crs[:], hashPos[:], block.ProposerID.Hash[:]) + } + return crypto.Keccak256Hash(crs[:], hashPos[:]) +} + +// VerifyCRSSignature verifies the CRS signature of types.Block. +func VerifyCRSSignature( + block *types.Block, crs common.Hash, npks *typesDKG.NodePublicKeys) bool { + hash := hashCRS(block, crs) + if block.Position.Round < dkgDelayRound { + return bytes.Compare(block.CRSSignature.Signature[:], hash[:]) == 0 + } + if npks == nil { + return false + } + pubKey, exist := npks.PublicKeys[block.ProposerID] + if !exist { + return false + } + return pubKey.VerifySignature(hash, block.CRSSignature) +} + +// HashPosition generates hash of a types.Position. +func HashPosition(position types.Position) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, position.Round) + + binaryHeight := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryHeight, position.Height) + + return crypto.Keccak256Hash( + binaryRound, + binaryHeight, + ) +} + +func hashDKGPrivateShare(prvShare *typesDKG.PrivateShare) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, prvShare.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, prvShare.Reset) + + return crypto.Keccak256Hash( + prvShare.ProposerID.Hash[:], + prvShare.ReceiverID.Hash[:], + binaryRound, + binaryReset, + prvShare.PrivateShare.Bytes(), + ) +} + +// VerifyDKGPrivateShareSignature verifies the signature of +// typesDKG.PrivateShare. +func VerifyDKGPrivateShareSignature( + prvShare *typesDKG.PrivateShare) (bool, error) { + hash := hashDKGPrivateShare(prvShare) + pubKey, err := crypto.SigToPub(hash, prvShare.Signature) + if err != nil { + return false, err + } + if prvShare.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +func hashDKGMasterPublicKey(mpk *typesDKG.MasterPublicKey) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, mpk.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, mpk.Reset) + + return crypto.Keccak256Hash( + mpk.ProposerID.Hash[:], + mpk.DKGID.GetLittleEndian(), + mpk.PublicKeyShares.MasterKeyBytes(), + binaryRound, + binaryReset, + ) +} + +// VerifyDKGMasterPublicKeySignature verifies DKGMasterPublicKey signature. +func VerifyDKGMasterPublicKeySignature( + mpk *typesDKG.MasterPublicKey) (bool, error) { + hash := hashDKGMasterPublicKey(mpk) + pubKey, err := crypto.SigToPub(hash, mpk.Signature) + if err != nil { + return false, err + } + if mpk.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +func hashDKGComplaint(complaint *typesDKG.Complaint) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, complaint.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, complaint.Reset) + + hashPrvShare := hashDKGPrivateShare(&complaint.PrivateShare) + + return crypto.Keccak256Hash( + complaint.ProposerID.Hash[:], + binaryRound, + binaryReset, + hashPrvShare[:], + ) +} + +// VerifyDKGComplaintSignature verifies DKGCompliant signature. +func VerifyDKGComplaintSignature( + complaint *typesDKG.Complaint) (bool, error) { + if complaint.Round != complaint.PrivateShare.Round { + return false, nil + } + if complaint.Reset != complaint.PrivateShare.Reset { + return false, nil + } + hash := hashDKGComplaint(complaint) + pubKey, err := crypto.SigToPub(hash, complaint.Signature) + if err != nil { + return false, err + } + if complaint.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + if !complaint.IsNack() { + return VerifyDKGPrivateShareSignature(&complaint.PrivateShare) + } + return true, nil +} + +func hashDKGPartialSignature(psig *typesDKG.PartialSignature) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, psig.Round) + + return crypto.Keccak256Hash( + psig.ProposerID.Hash[:], + binaryRound, + psig.Hash[:], + psig.PartialSignature.Signature[:], + ) +} + +// VerifyDKGPartialSignatureSignature verifies the signature of +// typesDKG.PartialSignature. +func VerifyDKGPartialSignatureSignature( + psig *typesDKG.PartialSignature) (bool, error) { + hash := hashDKGPartialSignature(psig) + pubKey, err := crypto.SigToPub(hash, psig.Signature) + if err != nil { + return false, err + } + if psig.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +func hashDKGMPKReady(ready *typesDKG.MPKReady) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, ready.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, ready.Reset) + + return crypto.Keccak256Hash( + ready.ProposerID.Hash[:], + binaryRound, + binaryReset, + ) +} + +// VerifyDKGMPKReadySignature verifies DKGMPKReady signature. +func VerifyDKGMPKReadySignature( + ready *typesDKG.MPKReady) (bool, error) { + hash := hashDKGMPKReady(ready) + pubKey, err := crypto.SigToPub(hash, ready.Signature) + if err != nil { + return false, err + } + if ready.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +func hashDKGFinalize(final *typesDKG.Finalize) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, final.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, final.Reset) + + return crypto.Keccak256Hash( + final.ProposerID.Hash[:], + binaryRound, + binaryReset, + ) +} + +func hashDKGSuccess(success *typesDKG.Success) common.Hash { + binaryRound := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRound, success.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, success.Reset) + + return crypto.Keccak256Hash( + success.ProposerID.Hash[:], + binaryRound, + binaryReset, + ) +} + +// VerifyDKGFinalizeSignature verifies DKGFinalize signature. +func VerifyDKGFinalizeSignature( + final *typesDKG.Finalize) (bool, error) { + hash := hashDKGFinalize(final) + pubKey, err := crypto.SigToPub(hash, final.Signature) + if err != nil { + return false, err + } + if final.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +// VerifyDKGSuccessSignature verifies DKGSuccess signature. +func VerifyDKGSuccessSignature( + success *typesDKG.Success) (bool, error) { + hash := hashDKGSuccess(success) + pubKey, err := crypto.SigToPub(hash, success.Signature) + if err != nil { + return false, err + } + if success.ProposerID != types.NewNodeID(pubKey) { + return false, nil + } + return true, nil +} + +// Rehash hashes the hash again and again and again... +func Rehash(hash common.Hash, count uint) common.Hash { + result := hash + for i := uint(0); i < count; i++ { + result = crypto.Keccak256Hash(result[:]) + } + return result +} |