github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/hasherstore.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:49</date>
    10  //</624342681161568256>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  package storage
    29  
    30  import (
    31  	"context"
    32  	"fmt"
    33  	"sync"
    34  
    35  	"github.com/ethereum/go-ethereum/crypto/sha3"
    36  	"github.com/ethereum/go-ethereum/swarm/chunk"
    37  	"github.com/ethereum/go-ethereum/swarm/storage/encryption"
    38  )
    39  
    40  type chunkEncryption struct {
    41  	spanEncryption encryption.Encryption
    42  	dataEncryption encryption.Encryption
    43  }
    44  
    45  type hasherStore struct {
    46  	store           ChunkStore
    47  	hashFunc        SwarmHasher
    48  	chunkEncryption *chunkEncryption
    49  hashSize        int   //
    50  refSize         int64 //
    51  	wg              *sync.WaitGroup
    52  	closed          chan struct{}
    53  }
    54  
    55  func newChunkEncryption(chunkSize, refSize int64) *chunkEncryption {
    56  	return &chunkEncryption{
    57  		spanEncryption: encryption.New(0, uint32(chunkSize/refSize), sha3.NewKeccak256),
    58  		dataEncryption: encryption.New(int(chunkSize), 0, sha3.NewKeccak256),
    59  	}
    60  }
    61  
    62  //
    63  //
    64  //
    65  func NewHasherStore(chunkStore ChunkStore, hashFunc SwarmHasher, toEncrypt bool) *hasherStore {
    66  	var chunkEncryption *chunkEncryption
    67  
    68  	hashSize := hashFunc().Size()
    69  	refSize := int64(hashSize)
    70  	if toEncrypt {
    71  		refSize += encryption.KeyLength
    72  		chunkEncryption = newChunkEncryption(chunk.DefaultSize, refSize)
    73  	}
    74  
    75  	return &hasherStore{
    76  		store:           chunkStore,
    77  		hashFunc:        hashFunc,
    78  		chunkEncryption: chunkEncryption,
    79  		hashSize:        hashSize,
    80  		refSize:         refSize,
    81  		wg:              &sync.WaitGroup{},
    82  		closed:          make(chan struct{}),
    83  	}
    84  }
    85  
    86  //
    87  //
    88  //
    89  func (h *hasherStore) Put(ctx context.Context, chunkData ChunkData) (Reference, error) {
    90  	c := chunkData
    91  	size := chunkData.Size()
    92  	var encryptionKey encryption.Key
    93  	if h.chunkEncryption != nil {
    94  		var err error
    95  		c, encryptionKey, err = h.encryptChunkData(chunkData)
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  	}
   100  	chunk := h.createChunk(c, size)
   101  
   102  	h.storeChunk(ctx, chunk)
   103  
   104  	return Reference(append(chunk.Addr, encryptionKey...)), nil
   105  }
   106  
   107  //
   108  //
   109  //
   110  func (h *hasherStore) Get(ctx context.Context, ref Reference) (ChunkData, error) {
   111  	key, encryptionKey, err := parseReference(ref, h.hashSize)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	toDecrypt := (encryptionKey != nil)
   116  
   117  	chunk, err := h.store.Get(ctx, key)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	chunkData := chunk.SData
   123  	if toDecrypt {
   124  		var err error
   125  		chunkData, err = h.decryptChunkData(chunkData, encryptionKey)
   126  		if err != nil {
   127  			return nil, err
   128  		}
   129  	}
   130  	return chunkData, nil
   131  }
   132  
   133  //
   134  //
   135  func (h *hasherStore) Close() {
   136  	close(h.closed)
   137  }
   138  
   139  //
   140  //
   141  //
   142  func (h *hasherStore) Wait(ctx context.Context) error {
   143  	<-h.closed
   144  	h.wg.Wait()
   145  	return nil
   146  }
   147  
   148  func (h *hasherStore) createHash(chunkData ChunkData) Address {
   149  	hasher := h.hashFunc()
   150  hasher.ResetWithLength(chunkData[:8]) //
   151  hasher.Write(chunkData[8:])           //
   152  	return hasher.Sum(nil)
   153  }
   154  
   155  func (h *hasherStore) createChunk(chunkData ChunkData, chunkSize int64) *Chunk {
   156  	hash := h.createHash(chunkData)
   157  	chunk := NewChunk(hash, nil)
   158  	chunk.SData = chunkData
   159  	chunk.Size = chunkSize
   160  
   161  	return chunk
   162  }
   163  
   164  func (h *hasherStore) encryptChunkData(chunkData ChunkData) (ChunkData, encryption.Key, error) {
   165  	if len(chunkData) < 8 {
   166  		return nil, nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData))
   167  	}
   168  
   169  	encryptionKey, err := encryption.GenerateRandomKey()
   170  	if err != nil {
   171  		return nil, nil, err
   172  	}
   173  
   174  	encryptedSpan, err := h.chunkEncryption.spanEncryption.Encrypt(chunkData[:8], encryptionKey)
   175  	if err != nil {
   176  		return nil, nil, err
   177  	}
   178  	encryptedData, err := h.chunkEncryption.dataEncryption.Encrypt(chunkData[8:], encryptionKey)
   179  	if err != nil {
   180  		return nil, nil, err
   181  	}
   182  	c := make(ChunkData, len(encryptedSpan)+len(encryptedData))
   183  	copy(c[:8], encryptedSpan)
   184  	copy(c[8:], encryptedData)
   185  	return c, encryptionKey, nil
   186  }
   187  
   188  func (h *hasherStore) decryptChunkData(chunkData ChunkData, encryptionKey encryption.Key) (ChunkData, error) {
   189  	if len(chunkData) < 8 {
   190  		return nil, fmt.Errorf("Invalid ChunkData, min length 8 got %v", len(chunkData))
   191  	}
   192  
   193  	decryptedSpan, err := h.chunkEncryption.spanEncryption.Decrypt(chunkData[:8], encryptionKey)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  
   198  	decryptedData, err := h.chunkEncryption.dataEncryption.Decrypt(chunkData[8:], encryptionKey)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  //
   204  	length := ChunkData(decryptedSpan).Size()
   205  	for length > chunk.DefaultSize {
   206  		length = length + (chunk.DefaultSize - 1)
   207  		length = length / chunk.DefaultSize
   208  		length *= h.refSize
   209  	}
   210  
   211  	c := make(ChunkData, length+8)
   212  	copy(c[:8], decryptedSpan)
   213  	copy(c[8:], decryptedData[:length])
   214  
   215  	return c[:length+8], nil
   216  }
   217  
   218  func (h *hasherStore) RefSize() int64 {
   219  	return h.refSize
   220  }
   221  
   222  func (h *hasherStore) storeChunk(ctx context.Context, chunk *Chunk) {
   223  	h.wg.Add(1)
   224  	go func() {
   225  		<-chunk.dbStoredC
   226  		h.wg.Done()
   227  	}()
   228  	h.store.Put(ctx, chunk)
   229  }
   230  
   231  func parseReference(ref Reference, hashSize int) (Address, encryption.Key, error) {
   232  	encryptedKeyLength := hashSize + encryption.KeyLength
   233  	switch len(ref) {
   234  	case KeyLength:
   235  		return Address(ref), nil, nil
   236  	case encryptedKeyLength:
   237  		encKeyIdx := len(ref) - encryption.KeyLength
   238  		return Address(ref[:encKeyIdx]), encryption.Key(ref[encKeyIdx:]), nil
   239  	default:
   240  		return nil, nil, fmt.Errorf("Invalid reference length, expected %v or %v got %v", hashSize, encryptedKeyLength, len(ref))
   241  	}
   242  
   243  }
   244