github.com/koko1123/flow-go-1@v0.29.6/model/flow/identifier.go (about)

     1  // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
     2  
     3  package flow
     4  
     5  import (
     6  	"encoding/binary"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"math/rand"
    10  	"reflect"
    11  
    12  	"github.com/ipfs/go-cid"
    13  	mh "github.com/multiformats/go-multihash"
    14  
    15  	"github.com/koko1123/flow-go-1/model/fingerprint"
    16  	"github.com/koko1123/flow-go-1/storage/merkle"
    17  	"github.com/onflow/flow-go/crypto"
    18  	"github.com/onflow/flow-go/crypto/hash"
    19  )
    20  
    21  const IdentifierLen = 32
    22  
    23  // Identifier represents a 32-byte unique identifier for an entity.
    24  type Identifier [IdentifierLen]byte
    25  
    26  // IdentifierFilter is a filter on identifiers.
    27  type IdentifierFilter func(Identifier) bool
    28  
    29  // IdentifierOrder is a sort for identifier
    30  type IdentifierOrder func(Identifier, Identifier) bool
    31  
    32  var (
    33  	// ZeroID is the lowest value in the 32-byte ID space.
    34  	ZeroID = Identifier{}
    35  )
    36  
    37  // HexStringToIdentifier converts a hex string to an identifier. The input
    38  // must be 64 characters long and contain only valid hex characters.
    39  func HexStringToIdentifier(hexString string) (Identifier, error) {
    40  	var identifier Identifier
    41  	i, err := hex.Decode(identifier[:], []byte(hexString))
    42  	if err != nil {
    43  		return identifier, err
    44  	}
    45  	if i != 32 {
    46  		return identifier, fmt.Errorf("malformed input, expected 32 bytes (64 characters), decoded %d", i)
    47  	}
    48  	return identifier, nil
    49  }
    50  
    51  func MustHexStringToIdentifier(hexString string) Identifier {
    52  	id, err := HexStringToIdentifier(hexString)
    53  	if err != nil {
    54  		panic(err)
    55  	}
    56  	return id
    57  }
    58  
    59  // String returns the hex string representation of the identifier.
    60  func (id Identifier) String() string {
    61  	return hex.EncodeToString(id[:])
    62  }
    63  
    64  // Format handles formatting of id for different verbs. This is called when
    65  // formatting an identifier with fmt.
    66  func (id Identifier) Format(state fmt.State, verb rune) {
    67  	switch verb {
    68  	case 'x', 's', 'v':
    69  		_, _ = state.Write([]byte(id.String()))
    70  	default:
    71  		_, _ = state.Write([]byte(fmt.Sprintf("%%!%c(%s=%s)", verb, reflect.TypeOf(id), id)))
    72  	}
    73  }
    74  
    75  // IsSampled is a utility method to sample entities based on their ids
    76  // the range is from [0, 64].
    77  // 0 is 100% (all data will be collected)
    78  // 1 is ~50%
    79  // 2 is ~25%
    80  // 3 is ~12.5%
    81  // ...
    82  // >64 is 0% (no data will be collected)
    83  func (id Identifier) IsSampled(sensitivity uint) bool {
    84  	if sensitivity > 64 {
    85  		return false
    86  	}
    87  	// take the first 8 bytes and check the first few bits based on sensitivity
    88  	// higher sensitivity means more bits has to be zero, means less number of samples
    89  	// sensitivity of zero, means everything is sampled
    90  	return binary.BigEndian.Uint64(id[:8])>>uint64(64-sensitivity) == 0
    91  }
    92  
    93  func (id Identifier) MarshalText() ([]byte, error) {
    94  	return []byte(id.String()), nil
    95  }
    96  
    97  func (id *Identifier) UnmarshalText(text []byte) error {
    98  	var err error
    99  	*id, err = HexStringToIdentifier(string(text))
   100  	return err
   101  }
   102  
   103  func HashToID(hash []byte) Identifier {
   104  	var id Identifier
   105  	copy(id[:], hash)
   106  	return id
   107  }
   108  
   109  // MakeID creates an ID from a hash of encoded data. MakeID uses `model.Fingerprint() []byte` to get the byte
   110  // representation of the entity, which uses RLP to encode the data. If the input defines its own canonical encoding by
   111  // implementing Fingerprinter, it uses that instead. That allows removal of non-unique fields from structs or
   112  // overwriting of the used encoder. We are using Fingerprint instead of the default encoding for two reasons: a) JSON
   113  // (the default encoding) does not specify an order for the elements of arrays and objects, which could lead to
   114  // different hashes depending on the JSON implementation and b) the Fingerprinter interface allows to exclude fields not
   115  // needed in the pre-image of the hash that comprises the Identifier, which could be different from the encoding for
   116  // sending entities in messages or for storing them.
   117  func MakeID(entity interface{}) Identifier {
   118  	// collect fingerprint of the entity
   119  	data := fingerprint.Fingerprint(entity)
   120  	// make ID from fingerprint
   121  	return MakeIDFromFingerPrint(data)
   122  }
   123  
   124  // MakeIDFromFingerPrint is similar to MakeID but skipping fingerprinting step.
   125  func MakeIDFromFingerPrint(fingerPrint []byte) Identifier {
   126  	var id Identifier
   127  	hash.ComputeSHA3_256((*[hash.HashLenSHA3_256]byte)(&id), fingerPrint)
   128  	return id
   129  }
   130  
   131  // PublicKeyToID creates an ID from a public key.
   132  func PublicKeyToID(pk crypto.PublicKey) (Identifier, error) {
   133  	var id Identifier
   134  	pkBytes := pk.Encode()
   135  	hash.ComputeSHA3_256((*[32]byte)(&id), pkBytes)
   136  	return id, nil
   137  }
   138  
   139  // GetIDs gets the IDs for a slice of entities.
   140  func GetIDs[T Entity](entities []T) IdentifierList {
   141  	ids := make([]Identifier, 0, len(entities))
   142  	for _, entity := range entities {
   143  		ids = append(ids, entity.ID())
   144  	}
   145  	return ids
   146  }
   147  
   148  func MerkleRoot(ids ...Identifier) Identifier {
   149  	var root Identifier
   150  	tree, _ := merkle.NewTree(IdentifierLen) // we verify in a unit test that constructor does not error for this paramter
   151  	for i, id := range ids {
   152  		val := make([]byte, 8)
   153  		binary.BigEndian.PutUint64(val, uint64(i))
   154  		_, _ = tree.Put(id[:], val) // Tree copies keys and values internally
   155  		// `Put` only errors for keys whose length does not conform to the pre-configured length. As
   156  		// Identifiers are fixed-sized arrays, errors are impossible here, which we also verify in a unit test.
   157  	}
   158  	hash := tree.Hash()
   159  	copy(root[:], hash)
   160  	return root
   161  }
   162  
   163  func CheckMerkleRoot(root Identifier, ids ...Identifier) bool {
   164  	computed := MerkleRoot(ids...)
   165  	return root == computed
   166  }
   167  
   168  func ConcatSum(ids ...Identifier) Identifier {
   169  	hasher := hash.NewSHA3_256()
   170  	for _, id := range ids {
   171  		_, _ = hasher.Write(id[:])
   172  	}
   173  	hash := hasher.SumHash()
   174  	return HashToID(hash)
   175  }
   176  
   177  func CheckConcatSum(sum Identifier, fps ...Identifier) bool {
   178  	computed := ConcatSum(fps...)
   179  	return sum == computed
   180  }
   181  
   182  // Sample returns random sample of length 'size' of the ids
   183  // [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
   184  func Sample(size uint, ids ...Identifier) []Identifier {
   185  	n := uint(len(ids))
   186  	dup := make([]Identifier, 0, n)
   187  	dup = append(dup, ids...)
   188  	// if sample size is greater than total size, return all the elements
   189  	if n <= size {
   190  		return dup
   191  	}
   192  	for i := uint(0); i < size; i++ {
   193  		j := uint(rand.Intn(int(n - i)))
   194  		dup[i], dup[j+i] = dup[j+i], dup[i]
   195  	}
   196  	return dup[:size]
   197  }
   198  
   199  func CidToId(c cid.Cid) (Identifier, error) {
   200  	decoded, err := mh.Decode(c.Hash())
   201  	if err != nil {
   202  		return ZeroID, fmt.Errorf("failed to decode CID: %w", err)
   203  	}
   204  
   205  	if decoded.Code != mh.SHA2_256 {
   206  		return ZeroID, fmt.Errorf("unsupported CID hash function: %v", decoded.Name)
   207  	}
   208  	if decoded.Length != IdentifierLen {
   209  		return ZeroID, fmt.Errorf("invalid CID length: %d", decoded.Length)
   210  	}
   211  
   212  	return HashToID(decoded.Digest), nil
   213  }
   214  
   215  func IdToCid(f Identifier) cid.Cid {
   216  	hash, _ := mh.Encode(f[:], mh.SHA2_256)
   217  	return cid.NewCidV0(hash)
   218  }
   219  
   220  func ByteSliceToId(b []byte) (Identifier, error) {
   221  	var id Identifier
   222  	if len(b) != IdentifierLen {
   223  		return id, fmt.Errorf("illegal length for a flow identifier %x: got: %d, expected: %d", b, len(b), IdentifierLen)
   224  	}
   225  
   226  	copy(id[:], b[:])
   227  
   228  	return id, nil
   229  }
   230  
   231  func ByteSlicesToIds(b [][]byte) (IdentifierList, error) {
   232  	total := len(b)
   233  	ids := make(IdentifierList, total)
   234  
   235  	for i := 0; i < total; i++ {
   236  		id, err := ByteSliceToId(b[i])
   237  		if err != nil {
   238  			return nil, err
   239  		}
   240  
   241  		ids[i] = id
   242  	}
   243  
   244  	return ids, nil
   245  }
   246  
   247  func IdsToBytes(identifiers []Identifier) [][]byte {
   248  	var byteIds [][]byte
   249  	for _, id := range identifiers {
   250  		tempID := id // avoid capturing loop variable
   251  		byteIds = append(byteIds, tempID[:])
   252  	}
   253  
   254  	return byteIds
   255  }