go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/llx/chunk.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package llx
     5  
     6  import (
     7  	"encoding/base64"
     8  	"encoding/binary"
     9  
    10  	"go.mondoo.com/cnquery/types"
    11  	"go.mondoo.com/cnquery/utils/sortx"
    12  	"golang.org/x/crypto/blake2b"
    13  )
    14  
    15  // Checksum computes the checksum of this chunk
    16  func (c *Chunk) ChecksumV1(code *CodeV1) string {
    17  	data := []byte(c.Id)
    18  
    19  	b := make([]byte, 4)
    20  	binary.LittleEndian.PutUint32(b, uint32(c.Call))
    21  	data = append(data, b...)
    22  
    23  	if c.Primitive != nil {
    24  		cs := c.Primitive.checksumV1(code)
    25  		data = append(data, cs...)
    26  	}
    27  
    28  	if c.Function != nil {
    29  		data = append(data, c.Function.checksumV1(code)...)
    30  	}
    31  
    32  	hash := blake2b.Sum512(data)
    33  	return base64.StdEncoding.EncodeToString(hash[:])
    34  }
    35  
    36  func (f *Function) checksumV1(code *CodeV1) []byte {
    37  	res := []byte(f.Type)
    38  
    39  	for i := range f.Args {
    40  		cs := f.Args[i].checksumV1(code)
    41  		res = append(res, cs...)
    42  	}
    43  
    44  	return res
    45  }
    46  
    47  func (p *Primitive) checksumV1(code *CodeV1) []byte {
    48  	ref, ok := p.RefV1()
    49  	if ok {
    50  		typ := types.Type(p.Type)
    51  		if typ == types.Ref {
    52  			refChecksum, ok := code.Checksums[int32(ref)]
    53  			if !ok {
    54  				panic("llx> cannot compute checksum for primitive, it doesn't seem to reference a variable on the stack")
    55  			}
    56  
    57  			return []byte(refChecksum)
    58  		}
    59  
    60  		if typ.Underlying() == types.FunctionLike {
    61  			refFunction := code.Functions[int32(ref)-1]
    62  			if !ok {
    63  				panic("llx> cannot compute checksum for primitive, it doesn't seem to reference a function on the stack")
    64  			}
    65  
    66  			return []byte(refFunction.Id)
    67  		}
    68  
    69  		panic("llx> received a reference of an unknown type in trying to calculate the checksum")
    70  	}
    71  
    72  	res := []byte(p.Type)
    73  	res = append(res, p.Value...)
    74  
    75  	for i := range p.Array {
    76  		entry := p.Array[i]
    77  		res = append(res, entry.checksumV1(code)...)
    78  	}
    79  
    80  	keys := sortx.Keys(p.Map)
    81  
    82  	for _, k := range keys {
    83  		v := p.Map[k]
    84  		res = append(res, k...)
    85  		res = append(res, v.checksumV1(code)...)
    86  	}
    87  
    88  	return res
    89  }
    90  
    91  // Checksum computes the checksum of this chunk
    92  func (c *Chunk) ChecksumV2(blockRef uint64, code *CodeV2) string {
    93  	data := []byte(c.Id)
    94  
    95  	b := make([]byte, 4)
    96  	binary.LittleEndian.PutUint32(b, uint32(c.Call))
    97  	data = append(data, b...)
    98  
    99  	if c.Primitive != nil {
   100  		cs := c.Primitive.checksumV2(code)
   101  		data = append(data, cs...)
   102  	}
   103  
   104  	if c.Function != nil {
   105  		data = append(data, c.Function.checksumV2(code)...)
   106  	}
   107  
   108  	hash := blake2b.Sum512(data)
   109  	return base64.StdEncoding.EncodeToString(hash[:])
   110  }
   111  
   112  func (f *Function) checksumV2(code *CodeV2) []byte {
   113  	res := []byte(f.Type)
   114  
   115  	if f.Binding != 0 {
   116  		ref := code.Checksums[f.Binding]
   117  		if ref == "" {
   118  			panic("cannot compute checksum for chunk, it doesn't seem to reference a function on the stack")
   119  		}
   120  		res = append(res, ref...)
   121  	}
   122  
   123  	for i := range f.Args {
   124  		cs := f.Args[i].checksumV2(code)
   125  		res = append(res, cs...)
   126  	}
   127  
   128  	return res
   129  }
   130  
   131  func (p *Primitive) checksumV2(code *CodeV2) []byte {
   132  	ref, ok := p.RefV2()
   133  	if ok {
   134  		typ := types.Type(p.Type)
   135  		if typ == types.Ref {
   136  			refChecksum, ok := code.Checksums[ref]
   137  			if !ok {
   138  				panic("llx> cannot compute checksum for primitive, it doesn't seem to reference a variable on the stack")
   139  			}
   140  
   141  			return []byte(refChecksum)
   142  		} else if typ.Underlying() == types.FunctionLike {
   143  			refChecksum := code.Blocks[(ref>>32)-1].checksum(code)
   144  			return []byte(refChecksum)
   145  
   146  		}
   147  
   148  		panic("llx> received a reference of an unknown type in trying to calculate the checksum")
   149  	}
   150  
   151  	res := []byte(p.Type)
   152  	res = append(res, p.Value...)
   153  
   154  	for i := range p.Array {
   155  		entry := p.Array[i]
   156  		res = append(res, entry.checksumV2(code)...)
   157  	}
   158  
   159  	keys := sortx.Keys(p.Map)
   160  	for _, k := range keys {
   161  		v := p.Map[k]
   162  		res = append(res, k...)
   163  		res = append(res, v.checksumV2(code)...)
   164  	}
   165  
   166  	return res
   167  }