github.com/ethersphere/bee/v2@v2.2.0/pkg/manifest/mantaray/marshal.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mantaray 6 7 import ( 8 "bytes" 9 "crypto/rand" 10 "encoding/binary" 11 "encoding/hex" 12 "encoding/json" 13 "errors" 14 "fmt" 15 ) 16 17 const ( 18 maxUint16 = ^uint16(0) 19 ) 20 21 // Version constants. 22 const ( 23 versionNameString = "mantaray" 24 versionCode01String = "0.1" 25 versionCode02String = "0.2" 26 27 versionSeparatorString = ":" 28 29 version01String = versionNameString + versionSeparatorString + versionCode01String // "mantaray:0.1" 30 version01HashString = "025184789d63635766d78c41900196b57d7400875ebe4d9b5d1e76bd9652a9b7" // pre-calculated version string, Keccak-256 31 32 version02String = versionNameString + versionSeparatorString + versionCode02String // "mantaray:0.2" 33 version02HashString = "5768b3b6a7db56d21d1abff40d41cebfc83448fed8d7e9b06ec0d3b073f28f7b" // pre-calculated version string, Keccak-256 34 ) 35 36 // Node header fields constants. 37 const ( 38 nodeObfuscationKeySize = 32 39 versionHashSize = 31 40 nodeRefBytesSize = 1 41 42 // nodeHeaderSize defines the total size of the header part 43 nodeHeaderSize = nodeObfuscationKeySize + versionHashSize + nodeRefBytesSize 44 ) 45 46 // Node fork constats. 47 const ( 48 nodeForkTypeBytesSize = 1 49 nodeForkPrefixBytesSize = 1 50 nodeForkHeaderSize = nodeForkTypeBytesSize + nodeForkPrefixBytesSize // 2 51 nodeForkPreReferenceSize = 32 52 nodePrefixMaxSize = nodeForkPreReferenceSize - nodeForkHeaderSize // 30 53 // "mantaray:0.2" 54 nodeForkMetadataBytesSize = 2 55 ) 56 57 var ( 58 version01HashBytes []byte 59 version02HashBytes []byte 60 zero32 []byte 61 ) 62 63 // nolint:gochecknoinits 64 func init() { 65 initVersion(version01HashString, &version01HashBytes) 66 initVersion(version02HashString, &version02HashBytes) 67 zero32 = make([]byte, 32) 68 } 69 70 func initVersion(hash string, bytes *[]byte) { 71 b, err := hex.DecodeString(hash) 72 if err != nil { 73 panic(err) 74 } 75 76 *bytes = make([]byte, versionHashSize) 77 copy(*bytes, b) 78 } 79 80 var ( 81 // ErrTooShort signals too short input. 82 ErrTooShort = errors.New("serialised input too short") 83 // ErrInvalidInput signals invalid input to serialise. 84 ErrInvalidInput = errors.New("input invalid") 85 // ErrInvalidVersionHash signals unknown version of hash. 86 ErrInvalidVersionHash = errors.New("invalid version hash") 87 // ErrInvalidManifest signals when malformed manifest contenet is supplied to Unmarshal function 88 ErrInvalidManifest = errors.New("malformed manifest contents") 89 ) 90 91 var obfuscationKeyFn = rand.Read 92 93 // SetObfuscationKeyFn allows configuring custom function for generating 94 // obfuscation key. 95 // 96 // NOTE: This should only be used in tests. 97 func SetObfuscationKeyFn(fn func([]byte) (int, error)) { 98 obfuscationKeyFn = fn 99 } 100 101 // MarshalBinary serialises the node 102 func (n *Node) MarshalBinary() (bytes []byte, err error) { 103 if n.forks == nil { 104 return nil, ErrInvalidInput 105 } 106 107 // header 108 109 headerBytes := make([]byte, nodeHeaderSize) 110 111 if len(n.obfuscationKey) == 0 { 112 // generate obfuscation key 113 obfuscationKey := make([]byte, nodeObfuscationKeySize) 114 for i := 0; i < nodeObfuscationKeySize; { 115 read, _ := obfuscationKeyFn(obfuscationKey[i:]) 116 i += read 117 } 118 n.obfuscationKey = obfuscationKey 119 } 120 copy(headerBytes[0:nodeObfuscationKeySize], n.obfuscationKey) 121 122 copy(headerBytes[nodeObfuscationKeySize:nodeObfuscationKeySize+versionHashSize], version02HashBytes) 123 124 headerBytes[nodeObfuscationKeySize+versionHashSize] = uint8(n.refBytesSize) 125 126 bytes = append(bytes, headerBytes...) 127 128 // entry 129 130 entryBytes := make([]byte, n.refBytesSize) 131 copy(entryBytes, n.entry) 132 bytes = append(bytes, entryBytes...) 133 134 // index 135 136 indexBytes := make([]byte, 32) 137 138 var index = &bitsForBytes{} 139 for k := range n.forks { 140 index.set(k) 141 } 142 copy(indexBytes, index.bytes()) 143 144 bytes = append(bytes, indexBytes...) 145 146 err = index.iter(func(b byte) error { 147 f := n.forks[b] 148 ref, err := f.bytes() 149 if err != nil { 150 return fmt.Errorf("%w on byte '%x'", err, []byte{b}) 151 } 152 bytes = append(bytes, ref...) 153 return nil 154 }) 155 if err != nil { 156 return nil, err 157 } 158 159 // perform XOR encryption on bytes after obfuscation key 160 xorEncryptedBytes := make([]byte, len(bytes)) 161 162 copy(xorEncryptedBytes, bytes[0:nodeObfuscationKeySize]) 163 164 for i := nodeObfuscationKeySize; i < len(bytes); i += nodeObfuscationKeySize { 165 end := i + nodeObfuscationKeySize 166 if end > len(bytes) { 167 end = len(bytes) 168 } 169 170 encrypted := encryptDecrypt(bytes[i:end], n.obfuscationKey) 171 copy(xorEncryptedBytes[i:end], encrypted) 172 } 173 174 return xorEncryptedBytes, nil 175 } 176 177 // bitsForBytes is a set of bytes represented as a 256-length bitvector 178 type bitsForBytes struct { 179 bits [32]byte 180 } 181 182 func (bb *bitsForBytes) bytes() (b []byte) { 183 b = append(b, bb.bits[:]...) 184 return b 185 } 186 187 func (bb *bitsForBytes) fromBytes(b []byte) { 188 copy(bb.bits[:], b) 189 } 190 191 func (bb *bitsForBytes) set(b byte) { 192 bb.bits[b/8] |= 1 << (b % 8) 193 } 194 195 //nolint:unused 196 func (bb *bitsForBytes) get(b byte) bool { 197 return bb.getUint8(b) 198 } 199 200 func (bb *bitsForBytes) getUint8(i uint8) bool { 201 return (bb.bits[i/8]>>(i%8))&1 > 0 202 } 203 204 func (bb *bitsForBytes) iter(f func(byte) error) error { 205 for i := uint8(0); ; i++ { 206 if bb.getUint8(i) { 207 if err := f(i); err != nil { 208 return err 209 } 210 } 211 if i == 255 { 212 return nil 213 } 214 } 215 } 216 217 // UnmarshalBinary deserialises a node 218 func (n *Node) UnmarshalBinary(data []byte) error { 219 if len(data) < nodeHeaderSize { 220 return ErrTooShort 221 } 222 223 n.obfuscationKey = append([]byte{}, data[0:nodeObfuscationKeySize]...) 224 225 // perform XOR decryption on bytes after obfuscation key 226 xorDecryptedBytes := make([]byte, len(data)) 227 228 copy(xorDecryptedBytes, data[0:nodeObfuscationKeySize]) 229 230 for i := nodeObfuscationKeySize; i < len(data); i += nodeObfuscationKeySize { 231 end := i + nodeObfuscationKeySize 232 if end > len(data) { 233 end = len(data) 234 } 235 236 decrypted := encryptDecrypt(data[i:end], n.obfuscationKey) 237 copy(xorDecryptedBytes[i:end], decrypted) 238 } 239 240 data = xorDecryptedBytes 241 242 // Verify version hash. 243 versionHash := data[nodeObfuscationKeySize : nodeObfuscationKeySize+versionHashSize] 244 245 if bytes.Equal(versionHash, version01HashBytes) { 246 247 refBytesSize := int(data[nodeHeaderSize-1]) 248 249 n.entry = append([]byte{}, data[nodeHeaderSize:nodeHeaderSize+refBytesSize]...) 250 offset := nodeHeaderSize + refBytesSize // skip entry 251 n.forks = make(map[byte]*fork) 252 bb := &bitsForBytes{} 253 bb.fromBytes(data[offset:]) 254 offset += 32 // skip forks 255 return bb.iter(func(b byte) error { 256 f := &fork{} 257 258 if len(data) < offset+nodeForkPreReferenceSize+refBytesSize { 259 err := fmt.Errorf("not enough bytes for node fork: %d (%d)", (len(data) - offset), (nodeForkPreReferenceSize + refBytesSize)) 260 return fmt.Errorf("%w on byte '%x': %w", err, []byte{b}, ErrInvalidManifest) 261 } 262 263 err := f.fromBytes(data[offset : offset+nodeForkPreReferenceSize+refBytesSize]) 264 if err != nil { 265 return fmt.Errorf("%w on byte '%x': %w", err, []byte{b}, ErrInvalidManifest) 266 } 267 268 n.forks[b] = f 269 offset += nodeForkPreReferenceSize + refBytesSize 270 return nil 271 }) 272 } else if bytes.Equal(versionHash, version02HashBytes) { 273 274 refBytesSize := int(data[nodeHeaderSize-1]) 275 276 n.entry = append([]byte{}, data[nodeHeaderSize:nodeHeaderSize+refBytesSize]...) 277 offset := nodeHeaderSize + refBytesSize // skip entry 278 // Currently we don't persist the root nodeType when we marshal the manifest, as a result 279 // the root nodeType information is lost on Unmarshal. This causes issues when we want to 280 // perform a path 'Walk' on the root. If there is more than 1 fork, the root node type 281 // is an edge, so we will deduce this information from index byte array 282 if !bytes.Equal(data[offset:offset+32], zero32) && !n.IsEdgeType() { 283 n.makeEdge() 284 } 285 n.forks = make(map[byte]*fork) 286 bb := &bitsForBytes{} 287 bb.fromBytes(data[offset:]) 288 offset += 32 // skip forks 289 return bb.iter(func(b byte) error { 290 f := &fork{} 291 292 if len(data) < offset+nodeForkTypeBytesSize { 293 return fmt.Errorf("not enough bytes for node fork: %d (%d) on byte '%x': %w", (len(data) - offset), (nodeForkTypeBytesSize), []byte{b}, ErrInvalidManifest) 294 } 295 296 nodeType := data[offset] 297 298 nodeForkSize := nodeForkPreReferenceSize + refBytesSize 299 300 if nodeTypeIsWithMetadataType(nodeType) { 301 if len(data) < offset+nodeForkPreReferenceSize+refBytesSize+nodeForkMetadataBytesSize { 302 return fmt.Errorf("not enough bytes for node fork: %d (%d) on byte '%x': %w", (len(data) - offset), (nodeForkPreReferenceSize + refBytesSize + nodeForkMetadataBytesSize), []byte{b}, ErrInvalidManifest) 303 } 304 305 metadataBytesSize := int(binary.BigEndian.Uint16(data[offset+nodeForkSize : offset+nodeForkSize+nodeForkMetadataBytesSize])) 306 307 nodeForkSize += nodeForkMetadataBytesSize 308 nodeForkSize += metadataBytesSize 309 310 if offset+nodeForkSize > len(data) { 311 return fmt.Errorf("not enough bytes for metadata: %w", ErrInvalidManifest) 312 } 313 314 err := f.fromBytes02(data[offset:offset+nodeForkSize], refBytesSize, metadataBytesSize) 315 if err != nil { 316 return fmt.Errorf("%w on byte '%x': %w", err, []byte{b}, ErrInvalidManifest) 317 } 318 } else { 319 if len(data) < offset+nodeForkPreReferenceSize+refBytesSize { 320 return fmt.Errorf("not enough bytes for node fork: %d (%d) on byte '%x'", (len(data) - offset), (nodeForkPreReferenceSize + refBytesSize), []byte{b}) 321 } 322 323 err := f.fromBytes(data[offset : offset+nodeForkSize]) 324 if err != nil { 325 return fmt.Errorf("%w on byte '%x': %w", err, []byte{b}, ErrInvalidManifest) 326 } 327 } 328 329 n.forks[b] = f 330 offset += nodeForkSize 331 return nil 332 }) 333 } 334 335 return fmt.Errorf("%x: %w", versionHash, ErrInvalidVersionHash) 336 } 337 338 func (f *fork) fromBytes(b []byte) error { 339 nodeType := b[0] 340 prefixLen := int(b[1]) 341 342 if prefixLen == 0 || prefixLen > nodePrefixMaxSize { 343 return fmt.Errorf("invalid prefix length: %d", prefixLen) 344 } 345 346 f.prefix = b[nodeForkHeaderSize : nodeForkHeaderSize+prefixLen] 347 f.Node = NewNodeRef(b[nodeForkPreReferenceSize:]) 348 f.Node.nodeType = nodeType 349 350 return nil 351 } 352 353 func (f *fork) fromBytes02(b []byte, refBytesSize, metadataBytesSize int) error { 354 nodeType := b[0] 355 prefixLen := int(b[1]) 356 357 if prefixLen == 0 || prefixLen > nodePrefixMaxSize { 358 return fmt.Errorf("invalid prefix length: %d", prefixLen) 359 } 360 361 f.prefix = b[nodeForkHeaderSize : nodeForkHeaderSize+prefixLen] 362 f.Node = NewNodeRef(b[nodeForkPreReferenceSize : nodeForkPreReferenceSize+refBytesSize]) 363 f.Node.nodeType = nodeType 364 365 if metadataBytesSize > 0 { 366 metadataBytes := b[nodeForkPreReferenceSize+refBytesSize+nodeForkMetadataBytesSize:] 367 368 metadata := make(map[string]string) 369 // using JSON encoding for metadata 370 err := json.Unmarshal(metadataBytes, &metadata) 371 if err != nil { 372 return err 373 } 374 375 f.Node.metadata = metadata 376 } 377 378 return nil 379 } 380 381 func (f *fork) bytes() (b []byte, err error) { 382 r := refBytes(f) 383 // using 1 byte ('f.Node.refBytesSize') for size 384 if len(r) > 256 { 385 err = fmt.Errorf("node reference size > 256: %d", len(r)) 386 return 387 } 388 b = append(b, f.Node.nodeType, uint8(len(f.prefix))) 389 390 prefixBytes := make([]byte, nodePrefixMaxSize) 391 copy(prefixBytes, f.prefix) 392 b = append(b, prefixBytes...) 393 394 refBytes := make([]byte, len(r)) 395 copy(refBytes, r) 396 b = append(b, refBytes...) 397 398 if f.Node.IsWithMetadataType() { 399 // using JSON encoding for metadata 400 metadataJSONBytes, err1 := json.Marshal(f.Node.metadata) 401 if err1 != nil { 402 return b, err1 403 } 404 405 metadataJSONBytesSizeWithSize := len(metadataJSONBytes) + nodeForkMetadataBytesSize 406 407 // pad JSON bytes if necessary 408 if metadataJSONBytesSizeWithSize < nodeObfuscationKeySize { 409 paddingLength := nodeObfuscationKeySize - metadataJSONBytesSizeWithSize 410 padding := make([]byte, paddingLength) 411 for i := range padding { 412 padding[i] = '\n' 413 } 414 metadataJSONBytes = append(metadataJSONBytes, padding...) 415 } else if metadataJSONBytesSizeWithSize > nodeObfuscationKeySize { 416 paddingLength := nodeObfuscationKeySize - metadataJSONBytesSizeWithSize%nodeObfuscationKeySize 417 padding := make([]byte, paddingLength) 418 for i := range padding { 419 padding[i] = '\n' 420 } 421 metadataJSONBytes = append(metadataJSONBytes, padding...) 422 } 423 424 metadataJSONBytesSize := len(metadataJSONBytes) 425 if metadataJSONBytesSize > int(maxUint16) { 426 return b, ErrMetadataTooLarge 427 } 428 429 mBytesSize := make([]byte, nodeForkMetadataBytesSize) 430 binary.BigEndian.PutUint16(mBytesSize, uint16(metadataJSONBytesSize)) 431 b = append(b, mBytesSize...) 432 433 b = append(b, metadataJSONBytes...) 434 } 435 436 return b, nil 437 } 438 439 var refBytes = nodeRefBytes 440 441 func nodeRefBytes(f *fork) []byte { 442 return f.Node.ref 443 } 444 445 // encryptDecrypt runs a XOR encryption on the input bytes, encrypting it if it 446 // hasn't already been, and decrypting it if it has, using the key provided. 447 func encryptDecrypt(input, key []byte) []byte { 448 output := make([]byte, len(input)) 449 450 for i := 0; i < len(input); i++ { 451 output[i] = input[i] ^ key[i%len(key)] 452 } 453 454 return output 455 }