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  }