Nyieun sistem verifikasi formal ti scratch. Bagian 1: Mesin Virtual Karakter dina PHP sareng Python

Verifikasi formal nyaéta verifikasi hiji program atanapi algoritma nganggo anu sanés.

Ieu mangrupikeun salah sahiji metode anu paling kuat anu ngamungkinkeun anjeun mendakan sadaya kerentanan dina program atanapi ngabuktikeun yén éta henteu aya.

Katerangan anu langkung rinci ngeunaan verifikasi formal tiasa ditingali dina conto ngarengsekeun masalah Ajag, Embe, jeung Kol dina artikel abdi saméméhna.

Dina artikel ieu kuring mindahkeun tina verifikasi formal masalah ka program jeung ngajelaskeun kumaha
kumaha aranjeunna bisa dirobah jadi sistem aturan formal otomatis.

Jang ngalampahkeun ieu, kuring nulis analog sorangan tina mesin virtual, ngagunakeun prinsip simbolis.

Ieu parses kode program tur narjamahkeun kana sistem persamaan (SMT), nu geus bisa direngsekeun programmatically.

Kusabab informasi ngeunaan itungan simbolis dibere dina Internet rada fragmentarily,
Kuring bakal ngajelaskeun sakeudeung naon éta.

Komputasi simbolis mangrupikeun cara pikeun ngaéksekusi program sakaligus dina rupa-rupa data sareng mangrupikeun alat utama pikeun verifikasi program formal.

Salaku conto, urang tiasa nyetél kaayaan input dimana argumen kahiji tiasa nyandak nilai positip, kadua négatip, nol katilu, sareng argumen kaluaran, contona, 42.

Itungan simbolis dina hiji ngajalankeun bakal masihan urang jawaban naha kasebut nyaéta dimungkinkeun pikeun urang pikeun ménta hasil nu dipikahoyong tur conto susunan parameter input misalna. Atawa buktina yén teu aya parameter sapertos kitu.

Sumawona, urang tiasa nyetél argumen input ka sadaya anu mungkin, sareng ngan ukur pilih kaluaran, contona, sandi administrator.

Dina hal ieu, urang bakal mendakan sadaya kerentanan program atanapi nampi bukti yén sandi administrator aman.

Perlu dicatet yén palaksanaan klasik tina program kalayan data input khusus mangrupikeun kasus khusus palaksanaan simbolis.

Ku alatan éta, VM karakter kuring ogé bisa dianggo dina modeu emulation tina mesin virtual baku.

Dina koméntar kana tulisan sateuacana tiasa mendakan kritik anu adil pikeun verifikasi formal kalayan diskusi ngeunaan kalemahanana.

Masalah utama nyaéta:

  1. Ledakan combinatorial, saprak verifikasi formal pamustunganana turun ka P = NP
  2. Ngolah sauran ka sistem file, jaringan sareng panyimpenan éksternal anu sanés langkung sesah diverifikasi
  3. Bugs dina spésifikasi, lamun nasabah atawa programmer dimaksudkeun hiji hal, tapi teu ngajelaskeun eta cukup akurat dina spésifikasi teknis.

Hasilna, program bakal diverifikasi sareng sasuai sareng spésifikasi, tapi bakal ngalakukeun hal anu béda-béda ti anu diarepkeun ku panyipta.

Kusabab dina artikel ieu kuring utamana tempo pamakéan verifikasi formal dina prakna, Kuring moal bang sirah kuring kana témbok pikeun ayeuna, sarta bakal milih sistem dimana pajeulitna algorithmic sarta jumlah panggero éksternal anu minimal.

Kusabab kontrak pinter paling cocog sareng syarat ieu, pilihanna murag kana kontrak RIDE tina platform Waves: aranjeunna henteu lengkep Turing, sareng pajeulitna maksimalna sacara artifisial terbatas.

Tapi urang bakal nganggap aranjeunna sacara éksklusif ti sisi téknis.

Salian sagalana, verifikasi formal bakal utamana di paménta pikeun sagala kontrak: biasana teu mungkin pikeun ngabenerkeun kasalahan kontrak sanggeus eta geus dibuka.
Sareng biaya kasalahan sapertos kitu tiasa pisan tinggi, sabab dana anu cukup ageung sering disimpen dina kontrak pinter.

mesin virtual simbolis kuring ditulis dina PHP jeung Python, sarta ngagunakeun Z3Prover ti Microsoft Panalungtikan pikeun ngajawab rumus SMT dihasilkeun.

Dina inti na mangrupakeun pilarian multi-transaksional kuat, nu
ngidinan Anjeun pikeun manggihan solusi atawa vulnerabilities, sanajan merlukeun loba transaksi.
malah Mythril, Salah sahiji kerangka simbolis pangkuatna pikeun manggihan kerentanan Ethereum, ngan ditambahkeun kamampuhan ieu sababaraha bulan kapengker.

Tapi eta sia noting yén kontrak éter leuwih kompleks jeung Turing lengkep.

PHP narjamahkeun kode sumber kontrak pinter RIDE kana skrip python, dimana programna dibere salaku sistem kontrak Z3 SMT anu cocog sareng kaayaan pikeun transisina:

Nyieun sistem verifikasi formal ti scratch. Bagian 1: Mesin Virtual Karakter dina PHP sareng Python

Ayeuna kuring bakal ngajelaskeun naon anu lumangsung di jero langkung jéntré.

Tapi ke heula, sababaraha kecap ngeunaan basa kontrak pinter RIDE.

Éta mangrupikeun basa pamrograman anu fungsional sareng éksprési anu puguh ku desain.
RIDE ngajalankeun di isolasi dina blockchain sarta bisa meunangkeun jeung nulis informasi ti gudang numbu ka dompét pamaké.

Anjeun tiasa ngagantelkeun kontrak RIDE ka unggal dompét, sareng hasil palaksanaan bakal ngan BENER atanapi PALSU.

BENER hartina kontrak pinter ngamungkinkeun transaksi, sarta PALSU hartina eta prohibits eta.
Conto saderhana: naskah tiasa ngalarang transfer upami kasaimbangan dompét kirang ti 100.

Salaku conto, kuring bakal nyandak Wolf, Embe, sareng Kol anu sami, tapi parantos dibere dina bentuk kontrak pinter.

Pamaké moal tiasa mundur artos tina dompét dimana kontrakna dipasang dugi ka anjeunna parantos ngirim sadayana ka sisi anu sanés.

#Извлекаем положение всех объектов из блокчейна
let contract = tx.sender
let human= extract(getInteger(contract,"human"))
let wolf= extract(getInteger(contract,"wolf"))
let goat= extract(getInteger(contract,"goat"))
let cabbage= extract(getInteger(contract,"cabbage"))

#Это так называемая дата-транзакция, в которой пользователь присылает новые 4 переменные.
#Контракт разрешит её только в случае если все объекты останутся в сохранности.
match tx {
case t:DataTransaction =>
   #Извлекаем будущее положение всех объектов из транзакции
   let newHuman= extract(getInteger(t.data,"human")) 
   let newWolf= extract(getInteger(t.data,"wolf"))
   let newGoat= extract(getInteger(t.data,"goat"))
   let newCabbage= extract(getInteger(t.data,"cabbage"))
   
   #0 обозначает, что объект на левом берегу, а 1 что на правом
   let humanSide= human == 0 || human == 1
   let wolfSide= wolf == 0 || wolf == 1
   let goatSide= goat == 0 || goat == 1
   let cabbageSide= cabbage == 0 || cabbage == 1
   let side= humanSide && wolfSide && goatSide && cabbageSide

   #Будут разрешены только те транзакции, где с козой никого нет в отсутствии фермера.
   let safeAlone= newGoat != newWolf && newGoat != newCabbage
   let safe= safeAlone || newGoat == newHuman
   let humanTravel= human != newHuman 

   #Способы путешествия фермера туда и обратно, с кем-то либо в одиночку.
   let t1= humanTravel && newWolf == wolf + 1 && newGoat == goat && newCabbage == cabbage 
   let t2= humanTravel && newWolf == wolf && newGoat == goat + 1 && newCabbage == cabbage
   let t3= humanTravel && newWolf == wolf && newGoat == goat && newCabbage == cabbage + 1
   let t4= humanTravel && newWolf == wolf - 1 && newGoat == goat && newCabbage == cabbage
   let t5= humanTravel && newWolf == wolf && newGoat == goat - 1 && newCabbage == cabbage
   let t6= humanTravel && newWolf == wolf && newGoat == goat && newCabbage == cabbage - 1
   let t7= humanTravel && newWolf == wolf && newGoat == goat && newCabbage == cabbage
   let objectTravel = t1 || t2 || t3 || t4 || t5 || t6 || t7
   
   #Последняя строка в разделе транзакции описывает разрешающее транзакцию условие.
   #Переменные транзакции должны иметь значения 1 или 0, все объекты должны
   #быть в безопасности, а фермер должен переплывать реку в одиночку 
   #или с кем-то на каждом шагу
   side && safe && humanTravel && objectTravel
case s:TransferTransaction =>
   #Транзакция вывода средств разрешена только в случае если все переплыли на другой берег
   human == 1 && wolf == 1 && goat == 1 && cabbage == 1

#Все прочие типы транзакций запрещены
case _ => false

}

PHP mimiti ékstrak sadaya variabel tina kontrak pinter dina bentuk konci maranéhanana jeung variabel éksprési Boolean pakait.

cabbage: extract ( getInteger ( contract , "cabbage" ) )
goat: extract ( getInteger ( contract , "goat" ) )
human: extract ( getInteger ( contract , "human" ) )
wolf: extract ( getInteger ( contract , "wolf" ) )
fState: human== 1 && wolf== 1 && goat== 1 && cabbage== 1
fState: 
wolf: 
goat: 
cabbage: 
cabbageSide: cabbage== 0 || cabbage== 1
human: extract ( getInteger ( contract , "human" ) )
newGoat: extract ( getInteger ( t.data , "goat" ) )
newHuman: extract ( getInteger ( t.data , "human" ) )
goatSide: goat== 0 || goat== 1
humanSide: human== 0 || human== 1
t7: humanTravel && newWolf== wolf && newGoat== goat && newCabbage== cabbage
t3: humanTravel && newWolf== wolf && newGoat== goat && newCabbage== cabbage + 1
t6: humanTravel && newWolf== wolf && newGoat== goat && newCabbage== cabbage - 1
t2: humanTravel && newWolf== wolf && newGoat== goat + 1 && newCabbage== cabbage
t5: humanTravel && newWolf== wolf && newGoat== goat - 1 && newCabbage== cabbage
t1: humanTravel && newWolf== wolf + 1 && newGoat== goat && newCabbage== cabbage
t4: humanTravel && newWolf== wolf - 1 && newGoat== goat && newCabbage== cabbage
safeAlone: newGoat != newWolf && newGoat != newCabbage
wolfSide: wolf== 0 || wolf== 1
humanTravel: human != newHuman
side: humanSide && wolfSide && goatSide && cabbageSide
safe: safeAlone || newGoat== newHuman
objectTravel: t1 || t2 || t3 || t4 || t5 || t6 || t7

PHP lajeng ngarobah kana pedaran Sistim Z3Prover SMT-cocog di Python.
Data dibungkus dina loop a, dimana variabel gudang narima indéks i, variabel urus indéks i + 1, sarta variabel jeung ungkapan diatur aturan pikeun transisi tina kaayaan saméméhna ka hareup.

Ieu mangrupikeun jantung mesin virtual urang, anu nyayogikeun mékanisme milarian multi-transaksional.

fState:  And( And( And( human[Steps]  ==  1 , wolf[Steps]  ==  1 )  , goat[Steps]  ==  1 )  , cabbage[Steps]  ==  1 )  
final:  fState[Steps] 
fState:   
wolf:   
goat:   
cabbage:   
cabbageSide:  Or( cabbage[i]  ==  0 , cabbage[i]  ==  1 )  
goatSide:  Or( goat[i]  ==  0 , goat[i]  ==  1 )  
humanSide:  Or( human[i]  ==  0 , human[i]  ==  1 )  
t7:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] )  , goat[i+1]  ==  goat[i] )  , cabbage  ==  cabbage[i] )  
t3:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] )  , goat[i+1]  ==  goat[i] )  , cabbage  ==  cabbage[i] + 1 )  
t6:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] )  , goat[i+1]  ==  goat[i] )  , cabbage  ==  cabbage[i] - 1 )  
t2:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] )  , goat[i+1]  ==  goat[i] + 1 )  , cabbage  ==  cabbage[i] )  
t5:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] )  , goat[i+1]  ==  goat[i] - 1 )  , cabbage  ==  cabbage[i] )  
t1:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] + 1 )  , goat[i+1]  ==  goat[i] )  , cabbage  ==  cabbage[i] )  
t4:  And( And( And( humanTravel[i] , wolf  ==  wolf[i] - 1 )  , goat[i+1]  ==  goat[i] )  , cabbage  ==  cabbage[i] )  
safeAlone:  And( goat[i+1] != wolf , goat[i+1] != cabbage )  
wolfSide:  Or( wolf[i]  ==  0 , wolf[i]  ==  1 )  
humanTravel:  human[i] != human[i+1] 
side:  And( And( And( humanSide[i] , wolfSide[i] )  , goatSide[i] )  , cabbageSide[i] )  
safe:  Or( safeAlone[i] , goat[i+1]  ==  human[i+1] )  
objectTravel:  Or( Or( Or( Or( Or( Or( t1[i] , t2[i] )  , t3[i] )  , t4[i] )  , t5[i] )  , t6[i] )  , t7[i] )  
data:  And( And( And( side[i] , safe[i] )  , humanTravel[i] )  , objectTravel[i] )  

Kaayaanana diurutkeun sareng diselapkeun kana template naskah anu dirancang pikeun ngajelaskeun sistem SMT dina Python.

template kosong


import json

from z3 import *

s = Solver()

  
  
    
Steps=7
Num= Steps+1

$code$



#template, only start rest
s.add(data + start)

#template
s.add(final)




ind = 0

f = open("/var/www/html/all/bin/python/log.txt", "a")



while s.check() == sat:
  ind = ind +1
  

  print ind
  m = s.model()
  print m

  print "traversing model..." 
  #for d in m.decls():
	#print "%s = %s" % (d.name(), m[d])

  
 
  f.write(str(m))
  f.write("nn")
  exit()
  #s.add(Or(goat[0] != s.model()[data[0]] )) # prevent next model from using the same assignment as a previous model



print "Total solution number: "
print ind  

f.close()
 


Pikeun kaayaan anu terakhir dina sakabéh ranté, aturan anu ditetepkeun dina bagian transaksi transfer diterapkeun.

Ieu ngandung harti yén Z3Prover bakal milarian set kaayaan anu pas anu tungtungna bakal ngantep dana ditarik tina kontrak.

Hasilna, urang otomatis nampi model SMT fungsi pinuh tina kontrak urang.
Anjeun tiasa ningali yén éta pisan sami sareng modél tina tulisan kuring sateuacana, anu ku kuring disusun sacara manual.

Rengse template


import json

from z3 import *

s = Solver()

  
  
    
Steps=7
Num= Steps+1

human = [ Int('human_%i' % (i + 1)) for i in range(Num) ]
wolf = [ Int('wolf_%i' % (i + 1)) for i in range(Num) ]
goat = [ Int('goat_%i' % (i + 1)) for i in range(Num) ]
cabbage = [ Int('cabbage_%i' % (i + 1)) for i in range(Num) ]
nothing= [  And( human[i] == human[i+1], wolf[i] == wolf[i+1], goat[i] == goat[i+1], cabbage[i] == cabbage[i+1] )   for i in range(Num-1) ]


start= [ human[0] == 1, wolf[0] == 0, goat[0] == 1, cabbage[0] == 0 ]

safeAlone= [  And( goat[i+1] != wolf[i+1] , goat[i+1] != cabbage[i+1] )   for i in range(Num-1) ]
safe= [  Or( safeAlone[i] , goat[i+1]  ==  human[i+1] )   for i in range(Num-1) ]
humanTravel= [  human[i] != human[i+1]  for i in range(Num-1) ]
cabbageSide= [  Or( cabbage[i]  ==  0 , cabbage[i]  ==  1 )   for i in range(Num-1) ]
goatSide= [  Or( goat[i]  ==  0 , goat[i]  ==  1 )   for i in range(Num-1) ]
humanSide= [  Or( human[i]  ==  0 , human[i]  ==  1 )   for i in range(Num-1) ]
t7= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] )  , goat[i+1]  ==  goat[i] )  , cabbage[i+1]  ==  cabbage[i] )   for i in range(Num-1) ]
t3= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] )  , goat[i+1]  ==  goat[i] )  , cabbage[i+1]  ==  cabbage[i] + 1 )   for i in range(Num-1) ]
t6= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] )  , goat[i+1]  ==  goat[i] )  , cabbage[i+1]  ==  cabbage[i] - 1 )   for i in range(Num-1) ]
t2= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] )  , goat[i+1]  ==  goat[i] + 1 )  , cabbage[i+1]  ==  cabbage[i] )   for i in range(Num-1) ]
t5= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] )  , goat[i+1]  ==  goat[i] - 1 )  , cabbage[i+1]  ==  cabbage[i] )   for i in range(Num-1) ]
t1= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] + 1 )  , goat[i+1]  ==  goat[i] )  , cabbage[i+1]  ==  cabbage[i] )   for i in range(Num-1) ]
t4= [  And( And( And( humanTravel[i] , wolf[i+1]  ==  wolf[i] - 1 )  , goat[i+1]  ==  goat[i] )  , cabbage[i+1]  ==  cabbage[i] )   for i in range(Num-1) ]
wolfSide= [  Or( wolf[i]  ==  0 , wolf[i]  ==  1 )   for i in range(Num-1) ]
side= [  And( And( And( humanSide[i] , wolfSide[i] )  , goatSide[i] )  , cabbageSide[i] )   for i in range(Num-1) ]
objectTravel= [  Or( Or( Or( Or( Or( Or( t1[i] , t2[i] )  , t3[i] )  , t4[i] )  , t5[i] )  , t6[i] )  , t7[i] )   for i in range(Num-1) ]
data= [ Or(  And( And( And( side[i] , safe[i] )  , humanTravel[i] )  , objectTravel[i] )   , nothing[i]) for i in range(Num-1) ]


fState=  And( And( And( human[Steps]  ==  1 , wolf[Steps]  ==  1 )  , goat[Steps]  ==  1 )  , cabbage[Steps]  ==  1 )  
final=  fState 




#template, only start rest
s.add(data + start)

#template
s.add(final)




ind = 0

f = open("/var/www/html/all/bin/python/log.txt", "a")



while s.check() == sat:
  ind = ind +1
  

  print ind
  m = s.model()
  print m

  print "traversing model..." 
  #for d in m.decls():
	#print "%s = %s" % (d.name(), m[d])

  
 
  f.write(str(m))
  f.write("nn")
  exit()
  #s.add(Or(goat[0] != s.model()[data[0]] )) # prevent next model from using the same assignment as a previous model



print "Total solution number: "
print ind  

f.close()
 


Saatos peluncuran, Z3Prover ngabéréskeun kontrak pinter sareng nyayogikeun ranté transaksi anu ngamungkinkeun urang mundur dana:

Winning transaction chain found:
Data transaction: human= 0, wolf= 0, goat= 1, cabbage= 0
Data transaction: human= 1, wolf= 0, goat= 1, cabbage= 1
Data transaction: human= 0, wolf= 0, goat= 0, cabbage= 1
Data transaction: human= 1, wolf= 1, goat= 0, cabbage= 1
Data transaction: human= 0, wolf= 1, goat= 0, cabbage= 1
Data transaction: human= 1, wolf= 1, goat= 1, cabbage= 1
Data transaction: human= 1, wolf= 1, goat= 1, cabbage= 1
Transfer transaction

Salian kontrak ferry, Anjeun bisa ékspérimén kalawan kontrak sorangan atawa coba conto basajan ieu, nu direngsekeun dina 2 transaksi.

let contract = tx.sender
let a= extract(getInteger(contract,"a"))
let b= extract(getInteger(contract,"b"))
let c= extract(getInteger(contract,"c"))
let d= extract(getInteger(contract,"d"))

match tx {
case t:DataTransaction =>
let na= extract(getInteger(t.data,"a")) 
let nb= extract(getInteger(t.data,"b"))
let nc= extract(getInteger(t.data,"c"))
let nd= extract(getInteger(t.data,"d"))
   
   nd == 0 || a == 100 - 5
case s:TransferTransaction =>
   ( a + b - c ) * d == 12

case _ => true

}

Kusabab ieu mangrupikeun versi anu pangheulana, sintaksisna terbatas pisan sareng tiasa aya bug.
Dina artikel di handap ieu, abdi rencanana nutupan ngembangkeun salajengna tina VM, sarta némbongkeun kumaha anjeun bisa nyieun kontrak pinter formal diverifikasi kalayan bantuan na, teu ngan ngajawab aranjeunna.

Mesin virtual karakter sayogi di http://2.59.42.98/hyperbox/
Saatos nempatkeun kodeu sumber VM simbolis dina urutan sareng nambihan koméntar di dinya, kuring badé nempatkeun éta dina GitHub pikeun aksés gratis.

sumber: www.habr.com

Tambahkeun komentar