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