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