github.com/amazechain/amc@v0.1.3/internal/vm/absint_cfg.go (about)

     1  package vm
     2  
     3  import (
     4  	"bytes"
     5  	"compress/zlib"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"log"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/holiman/uint256"
    14  )
    15  
    16  ////////////////////////
    17  
    18  const (
    19  	BotValue AbsValueKind = iota
    20  	TopValue
    21  	InvalidValue
    22  	ConcreteValue
    23  )
    24  
    25  func (d AbsValueKind) String() string {
    26  	return [...]string{"⊥", "⊤", "x", "AbsValue"}[d]
    27  }
    28  
    29  func (d AbsValueKind) hash() uint64 {
    30  	if d == BotValue {
    31  		return 0
    32  	} else if d == TopValue {
    33  		return 1
    34  	} else if d == InvalidValue {
    35  		return 2
    36  	} else if d == ConcreteValue {
    37  		return 3
    38  	} else {
    39  		panic("no hash found")
    40  	}
    41  }
    42  
    43  //////////////////////////////////////////////////
    44  
    45  type AbsValue struct {
    46  	kind  AbsValueKind
    47  	value *uint256.Int //only when kind=ConcreteValue
    48  	pc    int          //only when kind=TopValue
    49  }
    50  
    51  func (c0 AbsValue) String(abbrev bool) string {
    52  	if c0.kind == InvalidValue {
    53  		return c0.kind.String()
    54  	} else if c0.kind == BotValue {
    55  		return c0.kind.String()
    56  	} else if c0.kind == TopValue {
    57  		if !abbrev {
    58  			return fmt.Sprintf("%v%v", c0.kind.String(), c0.pc)
    59  		}
    60  		return c0.kind.String()
    61  	} else if c0.value.IsUint64() {
    62  		return strconv.FormatUint(c0.value.Uint64(), 10)
    63  	}
    64  	return "256bit"
    65  }
    66  
    67  func AbsValueTop(pc int) AbsValue {
    68  	return AbsValue{kind: TopValue, pc: pc}
    69  }
    70  
    71  func AbsValueInvalid() AbsValue {
    72  	return AbsValue{kind: InvalidValue}
    73  }
    74  
    75  func AbsValueConcrete(value uint256.Int) AbsValue {
    76  	return AbsValue{kind: ConcreteValue, value: &value}
    77  }
    78  
    79  func (c0 AbsValue) Eq(c1 AbsValue) bool {
    80  	if c0.kind != c1.kind {
    81  		return false
    82  	}
    83  
    84  	if c0.kind == ConcreteValue {
    85  		if !c0.value.Eq(c1.value) {
    86  			return false
    87  		}
    88  	}
    89  
    90  	return true
    91  }
    92  
    93  func (c0 AbsValue) hash() uint64 {
    94  	hash := 47 * c0.kind.hash()
    95  	if c0.kind == ConcreteValue {
    96  		hash += 57 * uint256Hash(c0.value)
    97  	}
    98  	return hash
    99  }
   100  
   101  func (c0 AbsValue) Stringify() string {
   102  	if c0.kind == InvalidValue || c0.kind == TopValue {
   103  		return c0.kind.String()
   104  	} else if c0.kind == ConcreteValue {
   105  		b, err := c0.value.MarshalText()
   106  		if err != nil {
   107  			log.Fatal("Can't unmarshall")
   108  		}
   109  		return string(b)
   110  	}
   111  
   112  	log.Fatal("Invalid abs value kind")
   113  	return ""
   114  }
   115  
   116  func AbsValueDestringify(s string) AbsValue {
   117  	if s == "⊤" {
   118  		return AbsValueTop(-1)
   119  	} else if s == "x" {
   120  		return AbsValueInvalid()
   121  	} else if strings.HasPrefix(s, "0x") {
   122  		var i uint256.Int
   123  		err := i.UnmarshalText([]byte(s))
   124  		if err != nil {
   125  			log.Fatal("Can't unmarshall")
   126  		}
   127  		return AbsValueConcrete(i)
   128  	}
   129  
   130  	log.Fatal("Invalid abs value kind")
   131  	return AbsValue{}
   132  }
   133  
   134  // ////////////////////////////////////////////////
   135  type astack struct {
   136  	values []AbsValue
   137  	hash   uint64
   138  }
   139  
   140  func newStack() *astack {
   141  	st := &astack{}
   142  	st.updateHash()
   143  	return st
   144  }
   145  
   146  func (s *astack) Copy() *astack {
   147  	newStack := &astack{}
   148  	newStack.values = append(newStack.values, s.values...)
   149  	newStack.hash = s.hash
   150  	return newStack
   151  }
   152  
   153  func uint256Hash(e *uint256.Int) uint64 {
   154  	return 19*e[0] + 23*e[1] + 29*e[2]*37*e[3]
   155  }
   156  
   157  func (s *astack) updateHash() {
   158  	s.hash = 0
   159  	for k, e := range s.values {
   160  		s.hash += uint64(k) * e.hash()
   161  	}
   162  }
   163  
   164  func (s *astack) Push(value AbsValue) {
   165  	rest := s.values
   166  	s.values = nil
   167  	s.values = append(s.values, value)
   168  	s.values = append(s.values, rest...)
   169  	s.updateHash()
   170  }
   171  
   172  func (s *astack) Pop(pc int) AbsValue {
   173  	res := s.values[0]
   174  	s.values = s.values[1:len(s.values)]
   175  	//s.values = append(s.values, AbsValueTop(pc, true))
   176  	s.updateHash()
   177  	return res
   178  }
   179  
   180  func (s *astack) String(abbrev bool) string {
   181  	strs := make([]string, 0)
   182  	for _, c := range s.values {
   183  		strs = append(strs, c.String(abbrev))
   184  	}
   185  	return strings.Join(strs, " ")
   186  }
   187  
   188  func (s *astack) Eq(s1 *astack) bool {
   189  	if s.hash != s1.hash {
   190  		return false
   191  	}
   192  
   193  	if len(s.values) != len(s1.values) {
   194  		return false
   195  	}
   196  
   197  	for i := 0; i < len(s.values); i++ {
   198  		if !s.values[i].Eq(s1.values[i]) {
   199  			return false
   200  		}
   201  	}
   202  	return true
   203  }
   204  
   205  func (s *astack) hasIndices(i ...int) bool {
   206  	for _, i := range i {
   207  		if !(i < len(s.values)) {
   208  			return false
   209  		}
   210  	}
   211  	return true
   212  }
   213  
   214  //////////////////////////////////////////////////
   215  
   216  type astate struct {
   217  	stackset    []*astack
   218  	anlyCounter int
   219  	worklistLen int
   220  }
   221  
   222  func emptyState() *astate {
   223  	return &astate{stackset: nil, anlyCounter: -1, worklistLen: -1}
   224  }
   225  
   226  func (state *astate) Copy() *astate {
   227  	newState := emptyState()
   228  	for _, stack := range state.stackset {
   229  		newState.stackset = append(newState.stackset, stack.Copy())
   230  	}
   231  	return newState
   232  }
   233  
   234  func botState() *astate {
   235  	st := emptyState()
   236  
   237  	botStack := newStack()
   238  	st.stackset = append(st.stackset, botStack)
   239  
   240  	return st
   241  }
   242  
   243  func ExistsIn(values []AbsValue, value AbsValue) bool {
   244  	for _, v := range values {
   245  		if value.Eq(v) {
   246  			return true
   247  		}
   248  	}
   249  	return false
   250  }
   251  
   252  func (state *astate) String(abbrev bool) string {
   253  	maxStackLen := 0
   254  	for _, stack := range state.stackset {
   255  		if maxStackLen < len(stack.values) {
   256  			maxStackLen = len(stack.values)
   257  		}
   258  	}
   259  
   260  	var elms []string
   261  	for i := 0; i < maxStackLen; i++ {
   262  		var elm []string
   263  		var values []AbsValue
   264  		for _, stack := range state.stackset {
   265  			if stack.hasIndices(i) {
   266  				value := stack.values[i]
   267  				if !ExistsIn(values, value) {
   268  					elm = append(elm, value.String(abbrev))
   269  					values = append(values, value)
   270  				}
   271  			}
   272  		}
   273  
   274  		var e string
   275  		if len(values) > 1 {
   276  			e = fmt.Sprintf("{%v}", strings.Join(elm, ","))
   277  		} else {
   278  			e = fmt.Sprintf("%v", strings.Join(elm, ","))
   279  		}
   280  		elms = append(elms, e)
   281  	}
   282  
   283  	elms = append(elms, fmt.Sprintf("%v%v%v", "|", len(state.stackset), "|"))
   284  	return strings.Join(elms, " ")
   285  }
   286  
   287  func (state *astate) Add(stack *astack) {
   288  	for _, existing := range state.stackset {
   289  		if existing.Eq(stack) {
   290  			return
   291  		}
   292  	}
   293  	state.stackset = append(state.stackset, stack)
   294  }
   295  
   296  //////////////////////////////////////////////////
   297  
   298  // -1 block id is invalid jump
   299  type CfgProofState struct {
   300  	Pc     int
   301  	Stacks [][]string
   302  }
   303  
   304  type CfgProofBlock struct {
   305  	Entry *CfgProofState
   306  	Exit  *CfgProofState
   307  	Preds []int
   308  	Succs []int
   309  }
   310  
   311  type CfgProof struct {
   312  	Blocks []*CfgProofBlock
   313  }
   314  
   315  func DeserializeCfgProof(proofBytes []byte) *CfgProof {
   316  	proof := CfgProof{}
   317  	err := json.Unmarshal(DecompressProof(proofBytes), &proof)
   318  	if err != nil {
   319  		log.Fatal("Cannot deserialize proof")
   320  	}
   321  	return &proof
   322  }
   323  
   324  func (proof *CfgProof) Serialize() []byte {
   325  	res, err := json.MarshalIndent(*proof, "", " ")
   326  	if err != nil {
   327  		log.Fatal("Cannot serialize proof")
   328  	}
   329  	return CompressProof(res)
   330  }
   331  
   332  func CompressProof(in []byte) []byte {
   333  	var b bytes.Buffer
   334  	w := zlib.NewWriter(&b)
   335  	_, err := w.Write(in)
   336  	if err != nil {
   337  		log.Fatal("cannot write proof")
   338  	}
   339  	err = w.Close()
   340  	if err != nil {
   341  		log.Fatal("cannot close file")
   342  	}
   343  	return b.Bytes()
   344  }
   345  
   346  func DecompressProof(in []byte) []byte {
   347  	reader := bytes.NewReader(in)
   348  	breader, err := zlib.NewReader(reader)
   349  	if err != nil {
   350  		log.Fatal("cannot read")
   351  	}
   352  
   353  	res, err := io.ReadAll(breader)
   354  	if err != nil {
   355  		log.Fatal("cannot read")
   356  	}
   357  	return res
   358  }
   359  
   360  func (proof *CfgProof) ToString() string {
   361  	return string(proof.Serialize())
   362  }
   363  
   364  // block.{Entry|Exit}.Pc in code, block.{Succs|Preds} in some block.{Entry}.Pc
   365  // Entry <= Exit
   366  // No overlap of blocks
   367  // Must have block starting at 0 with a empty state
   368  // Succs,Preds consistency
   369  // No duplicate succs
   370  // No duplicate preds
   371  // succs are sorted
   372  // preds are sorted
   373  func (proof *CfgProof) isValid() bool {
   374  	return true
   375  }
   376  
   377  func StringifyAState(st *astate) [][]string {
   378  	stacks := make([][]string, 0)
   379  
   380  	for _, astack := range st.stackset {
   381  		var stack []string
   382  		for _, v := range astack.values {
   383  			stack = append(stack, v.Stringify())
   384  		}
   385  		stacks = append(stacks, stack)
   386  	}
   387  
   388  	return stacks
   389  }
   390  
   391  func intoAState(ststr [][]string) *astate {
   392  	st := astate{}
   393  
   394  	for _, stack := range ststr {
   395  		s := astack{}
   396  		for _, vstr := range stack {
   397  			s.values = append(s.values, AbsValueDestringify(vstr))
   398  		}
   399  		s.updateHash()
   400  		st.Add(&s)
   401  	}
   402  
   403  	return &st
   404  }
   405  
   406  func Leq(st0 *astate, st1 *astate) bool {
   407  	for _, stack0 := range st0.stackset {
   408  		var found bool
   409  		for _, stack1 := range st1.stackset {
   410  			if stack0.Eq(stack1) {
   411  				found = true
   412  				break
   413  			}
   414  		}
   415  		if !found {
   416  			return false
   417  		}
   418  	}
   419  	return true
   420  }
   421  
   422  func Eq(st0 *astate, st1 *astate) bool {
   423  	return Leq(st0, st1) && Leq(st1, st0)
   424  }
   425  
   426  func Lub(st0 *astate, st1 *astate) *astate {
   427  	newState := emptyState()
   428  	for _, stack := range st0.stackset {
   429  		newState.Add(stack)
   430  	}
   431  	for _, stack := range st1.stackset {
   432  		newState.Add(stack)
   433  	}
   434  	return newState
   435  }