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 }